在 Android 上使用 RxNetty

來源:互聯網
上載者:User

在 Android 上使用 RxNetty
在 Android 上使用 RxNetty

Netty是由JBOSS提供的一個Java開源架構,是一個支援TCP/UDP/HTTP等網路通訊協定的通訊架構,和Mina類似,廣泛應用於RPC架構。RxNetty則是支援RxJava的Netty開源架構,現在我們來看一下在Android上如何使用RxNetty。

添加RxNetty

在 Android Studio 中添加 RxNetty 的依賴:

把RxNetty的tcp包加入到依賴,直接這樣編譯會有兩個問題,第一個問題是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

解決辦法:

dependencies {  ...  compile('io.reactivex:rxnetty-tcp:0.5.2-RC1') {    exclude group: 'org.openjdk.jmh'  }  ...}

另一個問題是引用的netty包中META-INF/下的部分檔案重複。
解決辦法:

  packagingOptions {    ...    exclude 'META-INF/INDEX.LIST'    exclude 'META-INF/BenchmarkList'    exclude 'META-INF/io.netty.versions.properties'    exclude 'META-INF/CompilerHints'    ...  }

到這裡RxNetty就成功添加到項目模組中了。接下來看看到底如何使用RxNetty。

如何使用

拿TCP協議舉例,用過Netty的都清楚建立串連的步驟:

        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();

自訂的協議需要我們自己實現編碼解碼Handler,還有最後處理資料的MessageHandler

@Sharablepublic class MessageHandler extends SimpleChannelInboundHandler {    @Override    public void messageReceived(ChannelHandlerContext ctx, Message msg)            throws Exception {            //處理訊息    }}

在RxNetty中可以不實現MessageHandler,因為通過註冊的觀察者可以得到最終解碼後的協議對象。
下面是RxNetty建立串連的方法:

  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);          }        });      }    });  }

上面的TCP用戶端建立了一個字串解碼器、一個字串編碼器,然後建立連結,在連結建立成功後把連結化物件connection儲存到mConnection方便後面發送資料,同時通知訂閱者socket串連成功。

在Android中不能在UI線程建立網路連結,就連InetSocketAddress類都不能在UI線程中建立,TcpClient.newClient(url, port)...createConnectionRequest()本身是一個Observable,但是由於方法newClient(url, port)中建立了InetSocketAddress類,Android嚴苛模式會報異常,所以上面建立連結的TcpClient方法在外層又包裹了一個Observable,讓它運行在IO線程等其它非UI線程才可以正常建立socket連結。

用來接收資料、發送資料的方法同樣返回一個Observable,代碼如下:

  public Observable receive() {    if (mConnection != null) {      return mConnection.getInput();    }    return null;  }  public Observable send(String s) {    return mConnection.writeString(Observable.just(s));  }

測試上面方法的用戶端代碼:

  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);          }        });      }    });  }

上面的程式碼封裝涵了讀、寫資料和重連等主要功能。
然後是建立服務端的代碼:

  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();  }

服務端代碼比較簡單,直接echo用戶端發來的資料。
關於線程,在Android中處理網路需要subscribeOn(Schedulers.io()),如果需要在UI線程展示則observeOn(AndroidSchedulers.mainThread())

最後,在Android上使用RxNetty大多數是因為沒有合適的socket用戶端架構,RxNetty也支援Http協議,Android上的Http協議的可選架構比較多,所以就不在這裡介紹了,想要瞭解的可以到這裡RxNetty。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.