Use RxNetty on Android
Use RxNetty on Android
Netty is a Java open-source framework provided by JBOSS and a communication framework that supports TCP, UDP, HTTP, and other network protocols. It is similar to Mina and widely used in RPC frameworks. RxNetty is a Netty open-source framework that supports RxJava. Now let's take a look at how to use RxNetty on Android.
Add RxNetty
Add RxNetty dependency to Android Studio:
Add the tcp package of RxNetty to the dependency. There are two problems with the direct compilation. The first problem is the repeated jar:
com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK THIRD-PARTYFile1: C:\Users\XXX.gradle\caches\modules-2\files-2.1\org.openjdk.jmh\jmh-core\1.11.2\f4f8cd9874f5cdbc272b715a381c57e65f67ddf2\jmh-core-1.11.2.jarFile2: C:\Users\XXX.gradle\caches\modules-2\files-2.1\org.openjdk.jmh\jmh-generator-annprocess\1.11.2\72d854bf76ba5e59596d4c887a6de48e7003bee2\jmh-generator-annprocess-1.11.2.jar
Solution:
dependencies { ... compile('io.reactivex:rxnetty-tcp:0.5.2-RC1') { exclude group: 'org.openjdk.jmh' } ...}
Another problem is that some files under the META-INF/in the referenced netty package are duplicated.
Solution:
packagingOptions { ... exclude 'META-INF/INDEX.LIST' exclude 'META-INF/BenchmarkList' exclude 'META-INF/io.netty.versions.properties' exclude 'META-INF/CompilerHints' ... }
RxNetty is successfully added to the project module. Next, let's take a look at how to use RxNetty.
How to Use
Take the TCP protocol as an example. If Netty is used, the connection creation steps are clear:
workerGroup = new NioEventLoopGroup(); Bootstrap boot = new Bootstrap(); boot.group(workerGroup) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer
() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast("decoder", new MessageDecoder()); p.addLast("encoder", new MessageEncoder()); p.addLast("handler", new MessageHandler()); } }); ChannelFuture f = boot.connect("localhost", 8888).syncUninterruptibly(); channel = f.channel();
Custom protocols require coding and decoding Handler and final data processing.MessageHandler:
@ Sharablepublic class MessageHandler extends SimpleChannelInboundHandler
{@ Override public void messageReceived (ChannelHandlerContext ctx, Message msg) throws Exception {// process Message }}
In RxNettyMessageHandlerBecause the registered observer can obtain the Protocol object after the final decoding.
The following is how RxNetty creates a connection:
Connection
mConnection; public Observable
connect(final String url, final int port) { return Observable.create(new Observable.OnSubscribe
() { @Override public void call(final Subscriber
subscriber) { TcpClient.newClient(url, port).
addChannelHandlerLast("decoder", new Func0
() { @Override public ChannelHandler call() { return new StringDecoder(); } }).
addChannelHandlerLast("encoder", new Func0
() { @Override public ChannelHandler call() { return new StringEncoder(); } }).createConnectionRequest().subscribe(new Observer
>() { @Override public void onCompleted() { subscriber.onCompleted(); } @Override public void onError(Throwable e) { subscriber.onError(e); } @Override public void onNext(Connection
connection) { mConnection = connection; subscriber.onNext(true); } }); } }); }
The preceding TCP client creates a string decoder, a string encoder, and a link. After the link is created successfullyconnectionSavemConnectionSend data later and notify the subscriber that the socket connection is successful.
In Android, you cannot create network links in the UI thread.InetSocketAddressClasses cannot be created in the UI thread,TcpClient.newClient(url, port)...createConnectionRequest()Itself isObservableBut because of the MethodnewClient(url, port)CreatedInetSocketAddressClass, Android strict mode will report an exception, so the TcpClient method created above contains anotherObservableAllows it to run in the IO thread and other non-UI threads to create socket links normally.
The method used to receive and send data also returns an Observable. The Code is as follows:
public Observable
receive() { if (mConnection != null) { return mConnection.getInput(); } return null; } public Observable
send(String s) { return mConnection.writeString(Observable.just(s)); }
Test the client code of the above method:
public void rxNettyClientTest() { connect("localhost", 60000).subscribe(new Observer
() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { //reconnect Observable.timer(1, TimeUnit.SECONDS).subscribe(new Action1
() { @Override public void call(Long aLong) { if (mConnection != null) mConnection.closeNow(); rxNettyClientTest(); } }); System.out.println("reconnect"); } @Override public void onNext(Boolean aBoolean) { //send data send("hello world!").subscribe(new Action1
() { @Override public void call(Void aVoid) { System.out.println("send success!"); } }); //receive data receive().subscribe(new Observer
() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { //reconnect Observable.timer(1, TimeUnit.SECONDS).subscribe(new Action1
() { @Override public void call(Long aLong) { if (mConnection != null) mConnection.closeNow(); rxNettyClientTest(); } }); System.out.println("reconnect"); } @Override public void onNext(String s) { System.out.println("receive:" + s); } }); } }); }
The above code includes reading, writing data, reconnecting, and other main functions.
Then, create the server code:
public void rxNettyServerTest() { TcpServer
server; server = TcpServer.newServer(60000).
addChannelHandlerLast("string-decoder", new Func0
() { @Override public ChannelHandler call() { return new StringDecoder(); } }).
addChannelHandlerLast("string-encoder", new Func0
() { @Override public ChannelHandler call() { return new StringEncoder(); } }).start(new ConnectionHandler
() { @Override public Observable
handle(Connection
newConnection) { return newConnection.writeStringAndFlushOnEach( newConnection.getInput().map(new Func1
() { @Override public String call(String s) { System.out.println("receive:" + s); return "echo=> " + s; } })); } }); server.awaitShutdown(); }
The server code is relatively simple, and the data sent from the client is directly echo.
About threads, processing network needs in AndroidsubscribeOn(Schedulers.io()), If you want to display it in the UI threadobserveOn(AndroidSchedulers.mainThread()).
Finally, the majority of RxNetty is used on Android because there is no suitable socket Client framework, and RxNetty also supports the Http protocol. There are many optional Http frameworks on Android, so we will not introduce it here, for more information, see RxNetty.