日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Netty HTTP on Android

發(fā)布時(shí)間:2024/4/11 Android 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Netty HTTP on Android 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Netty是一個(gè)NIO的客戶端服務(wù)器框架,它使我們可以快速而簡(jiǎn)單地開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用程序,比如協(xié)議服務(wù)器和客戶端。它大大簡(jiǎn)化了網(wǎng)絡(luò)編程,比如TCP和UDP socket服務(wù)器。

“快速而簡(jiǎn)單”并不意味著開(kāi)發(fā)出來(lái)的應(yīng)用可維護(hù)性或性能不好。Netty已經(jīng)實(shí)現(xiàn)了大量的協(xié)議,比如FTP,SMTP,HTTP,以及各種基于二進(jìn)制和文本的傳統(tǒng)協(xié)議??梢哉f(shuō)Netty已經(jīng)找到了一種方法來(lái)實(shí)現(xiàn)簡(jiǎn)單的開(kāi)發(fā),高性能,穩(wěn)定性,靈活性而不需要做妥協(xié)。

Netty的結(jié)構(gòu)大體如下圖這樣:


Netty Structure

就設(shè)計(jì)而言,Netty給不同的傳輸類型,不管是阻塞的還是非阻塞的,提供了統(tǒng)一的接口。它基于一個(gè)靈活的和可擴(kuò)展的事件模型,這使得處理不同邏輯的部分可以有效的隔離開(kāi)來(lái)。它具有高度可定制的線程模型 - 單線程,一個(gè)或多個(gè)線程池,比如SEDA。它還提供無(wú)連接的datagram socket支持。

如Netty這般,功能如此強(qiáng)大,性能如此優(yōu)良的網(wǎng)絡(luò)庫(kù),不用在Android上真是可惜了。這里我們就嘗試將Netty用在Android上。

下載Netty

首先是下載Netty。Netty的官網(wǎng)地址,我們可以在這里找到下載Netty的地址,當(dāng)然還有許許多多的文檔。這里使用了當(dāng)前4.1.x最新版的Netty 4.1.4,下載地址:

http://dl.bintray.com/netty/downloads/netty-4.1.4.Final.tar.bz2

解壓之后,為了省事,直接將netty-4.1.4.Final/jar/all-in-one/下的netty-all-4.1.4.Final.jar拷貝進(jìn)了工程下app module的libs目錄下。

Netty的簡(jiǎn)單使用

不出意外,直接通過(guò)編譯。接著我們就參考netty/example/src/main/java/io/netty/example/http/snoop中client部分的代碼,將Netty用起來(lái),這主要有如下幾個(gè)類:

package io.netty.example.http.snoop;import java.net.URI; import java.net.URISyntaxException;import javax.net.ssl.SSLException;import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.InsecureTrustManagerFactory;public class HttpClient {public static final String TAG = "NettyClient";public static void getResponse(final String url) {new Thread() {@Overridepublic void run() {try {URI uri = new URI(url);String scheme = uri.getScheme() == null ? "http" : uri.getScheme();String host = uri.getHost();int port = uri.getPort();if (port == -1) {if ("http".equalsIgnoreCase(scheme)) {port = 80;} else if ("https".equalsIgnoreCase(scheme)) {port = 443;}}if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {System.err.println("Only HTTP(S) is supported.");return;}final boolean ssl = "https".equalsIgnoreCase(scheme);final SslContext sslCtx;if (ssl) {sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();} else {sslCtx = null;}EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new HttpClientInitializer(sslCtx));// Make the connection attempt.Channel channel = bootstrap.connect(host, port).sync().channel();// Prepare the HTTP request.DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1,HttpMethod.GET, url);request.headers().set(HttpHeaderNames.HOST, host);request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderNames.KEEP_ALIVE);request.headers().set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);// Send the HTTP request.channel.writeAndFlush(request);// Wait for the server to close the connection.channel.closeFuture().sync();} finally {group.shutdownGracefully();}} catch (URISyntaxException e) {} catch (SSLException e) {} catch (InterruptedException e) {}}}.start();} }

這個(gè)class提供給外部調(diào)用的接口。使用者可以傳入U(xiǎn)RL,將借由這個(gè)類,通過(guò)Netty來(lái)訪問(wèn)網(wǎng)絡(luò)并獲取響應(yīng)。然后來(lái)看HttpClientInitializer:

package io.netty.example.http.snoop;import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpContentDecompressor; import io.netty.handler.ssl.SslContext;public class HttpClientInitializer extends ChannelInitializer<SocketChannel> {private final SslContext sslCtx;public HttpClientInitializer(SslContext sslCtx) {this.sslCtx = sslCtx;}@Overridepublic void initChannel(SocketChannel ch) {ChannelPipeline p = ch.pipeline();// Enable HTTPS if necessary.if (sslCtx != null) {p.addLast(sslCtx.newHandler(ch.alloc()));}p.addLast(new HttpClientCodec());// Remove the following line if you don't want automatic content decompression.p.addLast(new HttpContentDecompressor());// Uncomment the following line if you don't want to handle HttpContents.//p.addLast(new HttpObjectAggregator(1048576));p.addLast(new HttpClientHandler());} }

這個(gè)class負(fù)責(zé)對(duì)Channel的Pipeline進(jìn)行初始化,這其中最關(guān)鍵的是HttpClientHandler:

package io.netty.example.http.snoop;import android.util.Log;import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.LastHttpContent; import io.netty.util.CharsetUtil;public class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> {@Overridepublic void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {if (msg instanceof HttpResponse) {HttpResponse response = (HttpResponse) msg;Log.i(HttpClient.TAG, "STATUS: " + response.status());Log.i(HttpClient.TAG, "VERSION: " + response.protocolVersion());if (!response.headers().isEmpty()) {for (CharSequence name: response.headers().names()) {for (CharSequence value: response.headers().getAll(name)) {Log.i(HttpClient.TAG, "HEADER: " + name + " = " + value);}}}}if (msg instanceof HttpContent) {HttpContent content = (HttpContent) msg;String responseContent = content.content().toString(CharsetUtil.UTF_8);Log.i(HttpClient.TAG, responseContent);if (content instanceof LastHttpContent) {ctx.close();}}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();} }

我們正是通過(guò)實(shí)現(xiàn)HttpClientHandler,而獲取到Netty返回給我們的響應(yīng)的。

在我們的Android應(yīng)用代碼中調(diào)用HttpClient來(lái)通過(guò)Netty從網(wǎng)絡(luò)獲取響應(yīng):

package io.netty.example.http.snoop;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private TextView mTextScreen;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnGetIpInfo = (Button) findViewById(R.id.btn_get_ip_info_with_netty);btnGetIpInfo.setOnClickListener(mBtnClickListener);mTextScreen = (TextView) findViewById(R.id.text_screen);}View.OnClickListener mBtnClickListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {String url = "http://ip.taobao.com/service/getIpInfo.php?ip=123.58.191.68";mTextScreen.setText("To access " + url);Log.i(TAG, "To access " + url);if (R.id.btn_get_ip_info_with_netty == v.getId()) {HttpClient.getResponse(url);}}}; }

當(dāng)然不能忘記了在AndroidManifest.xml中添加對(duì)INTERNET權(quán)限的請(qǐng)求:

<uses-permission android:name="android.permission.INTERNET"/>

做完了所有這些之后,Netty基本上就可以跑起來(lái)了。不過(guò)意外還是發(fā)生了:

08-10 10:13:33.670 17720-17720/io.netty.example.http.snoop6.myapplication I/MainActivity: To access http://ip.taobao.com/service/getIpInfo.php?ip=123.58.191.68 08-10 10:13:33.818 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: java.lang.NoClassDefFoundError: com.jcraft.jzlib.Inflater 08-10 10:13:33.818 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.compression.JZlibDecoder.<init>(JZlibDecoder.java:27) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.compression.ZlibCodecFactory.newZlibDecoder(ZlibCodecFactory.java:122) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.http.HttpContentDecompressor.newContentDecoder(HttpContentDecompressor.java:57) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.http.HttpContentDecoder.decode(HttpContentDecoder.java:87) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.http.HttpContentDecoder.decode(HttpContentDecoder.java:46) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:88) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:280) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:396) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) 08-10 10:13:33.826 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:571) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:474) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:428) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:398) 08-10 10:13:33.834 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:877) 08-10 10:13:33.841 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144) 08-10 10:13:33.841 17720-18708/io.netty.example.http.snoop6.myapplication W/System.err: at java.lang.Thread.run(Thread.java:841) 08-10 10:13:33.841 17720-18708/io.netty.example.http.snoop6.myapplication I/NettyClient: --------- beginning of /dev/log/system 08-10 10:35:02.162 17720-17720/io.netty.example.http.snoop6.myapplication I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@41c10f28 time:1282964865

有一個(gè)class com.jcraft.jzlib.Inflater找不到。這還需要添加對(duì)jzlib的依賴:

compile 'com.jcraft:jzlib:1.1.2'

至此順利地將Netty跑起來(lái):

{"code":0,"data":{"country":"中國(guó)","country_id":"CN","area":"華東","area_id":"300000","region":"浙江省","region_id":"330000","city":"杭州市","city_id":"330100","county":"","county_id":"-1","isp":"網(wǎng)易網(wǎng)絡(luò)","isp_id":"1000119","ip":"123.58.191.68"} }

Netty的裁剪

Netty很強(qiáng)大,all-in-one jar用起來(lái)很方便,這很不錯(cuò)。但all-in-one jar有點(diǎn)大,其中包含的一些諸如對(duì)memcache,redis,stomp,sctp和udt等的支持,我們?cè)谝苿?dòng)端并不會(huì)用掉。因而需要對(duì)它做一點(diǎn)裁剪。

既然不能用all-in-one包,那就把需要的幾個(gè)jar文件單獨(dú)copy進(jìn)我們的工程好了。對(duì)于android而言,目測(cè)netty-4.1.4.Final/jar/下我們需要拷貝的jar文件主要有下面這些:

netty-codec-4.1.4.Final.jar netty-codec-http-4.1.4.Final.jar netty-codec-http2-4.1.4.Final.jar netty-codec-socks-4.1.4.Final.jar netty-common-4.1.4.Final.jar netty-handler-4.1.4.Final.jar netty-transport-4.1.4.Final.jar

用這些文件來(lái)替換之前的netty-all-4.1.4.Final.jar。遇到了編譯錯(cuò)誤:

:app:compileDebugJavaWithJavac Full recompilation is required because at least one of the classes of removed jar 'netty-all-4.1.4.Final.jar' requires it. Analysis took 0.364 secs. /media/data/MyProjects/MyApplication/app/src/main/java/io/netty/example/http/snoop/myapplication/HttpClient.java:67: 錯(cuò)誤: 無(wú)法訪問(wèn)ByteBufHolderrequest.headers().set(HttpHeaderNames.HOST, host);^找不到io.netty.buffer.ByteBufHolder的類文件 /media/data/MyProjects/MyApplication/app/src/main/java/io/netty/example/http/snoop/myapplication/HttpClientInitializer.java:39: 錯(cuò)誤: 無(wú)法訪問(wèn)ByteBufAllocatorp.addLast(sslCtx.newHandler(ch.alloc()));^找不到io.netty.buffer.ByteBufAllocator的類文件 /media/data/MyProjects/MyApplication/app/src/main/java/io/netty/example/http/snoop/myapplication/HttpClientHandler.java:48: 錯(cuò)誤: 找不到符號(hào)String responseContent = content.content().toString(CharsetUtil.UTF_8);^符號(hào): 方法 content()位置: 類型為HttpContent的變量 content 注: /media/data/MyProjects/MyApplication/app/src/main/java/io/netty/example/http/snoop/myapplication/HttpClient.java使用或覆蓋了已過(guò)時(shí)的 API。 注: 有關(guān)詳細(xì)信息, 請(qǐng)使用 -Xlint:deprecation 重新編譯。 3 個(gè)錯(cuò)誤 :app:compileDebugJavaWithJavac FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:compileDebugJavaWithJavac'. > Compilation failed; see the compiler error output for details.* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILED

看來(lái)是少了一些東西了,ByteBufHolder。那就把netty-buffer-4.1.4.Final.jar也加進(jìn)工程里。再次編譯,繼續(xù)出錯(cuò),這是在產(chǎn)生APK時(shí)遇到了麻煩:

:app:transformResourcesWithMergeJavaResForDebug FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'. > com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/INDEX.LISTFile1: /media/data/MyProjects/MyApplication/app/libs/netty-codec-4.1.4.Final.jarFile2: /media/data/MyProjects/MyApplication/app/libs/netty-transport-4.1.4.Final.jarFile3: /media/data/MyProjects/MyApplication/app/libs/netty-buffer-4.1.4.Final.jarFile4: /media/data/MyProjects/MyApplication/app/libs/netty-codec-socks-4.1.4.Final.jarFile5: /media/data/MyProjects/MyApplication/app/libs/netty-handler-4.1.4.Final.jarFile6: /media/data/MyProjects/MyApplication/app/libs/netty-codec-http2-4.1.4.Final.jarFile7: /media/data/MyProjects/MyApplication/app/libs/netty-codec-http-4.1.4.Final.jar* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 15.352 secs Duplicate files copied in APK META-INF/INDEX.LISTFile1: /media/data/MyProjects/MyApplication/app/libs/netty-codec-4.1.4.Final.jarFile2: /media/data/MyProjects/MyApplication/app/libs/netty-transport-4.1.4.Final.jarFile3: /media/data/MyProjects/MyApplication/app/libs/netty-buffer-4.1.4.Final.jarFile4: /media/data/MyProjects/MyApplication/app/libs/netty-codec-socks-4.1.4.Final.jarFile5: /media/data/MyProjects/MyApplication/app/libs/netty-handler-4.1.4.Final.jarFile6: /media/data/MyProjects/MyApplication/app/libs/netty-codec-http2-4.1.4.Final.jarFile7: /media/data/MyProjects/MyApplication/app/libs/netty-codec-http-4.1.4.Final.jar11:03:39: External task execution finished 'assembleDebug'.

總是報(bào)Duplicate files copied in APK META-INF/INDEX.LIST的錯(cuò)誤。這主要是因?yàn)檫@些jar文件里,不同的jar文件中的META-INF/INDEX.LIST包含了相同的內(nèi)容所致。這需要在build.gradle中的android元素里添加如下的配置:

packagingOptions {exclude 'META-INF/INDEX.LIST'}

再次編譯,這次則是包Duplicate files copied in APK META-INF/io.netty.versions.properties。這證明了前面的方法是行之有效的,于是把META-INF/io.netty.versions.properties也加進(jìn)packagingOptions的exclude列表:

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

再次編譯,編譯通過(guò)。但是在運(yùn)行的時(shí)候遇到了一點(diǎn)小麻煩:

11:29:59.685 9005-9050/com.example.hanpfei0306.myapplication W/dalvikvm: threadid=11: thread exiting with uncaught exception (group=0x41959ce0) 08-11 11:29:59.685 9005-9050/com.example.hanpfei0306.myapplication E/AndroidRuntime: FATAL EXCEPTION: Thread-1197Process: com.example.hanpfei0306.myapplication, PID: 9005java.lang.NoClassDefFoundError: io.netty.resolver.DefaultAddressResolverGroupat io.netty.bootstrap.Bootstrap.<clinit>(Bootstrap.java:53)at com.example.hanpfei0306.myapplication.HttpClient$1.run(HttpClient.java:57)

提示找不到class io.netty.resolver.DefaultAddressResolverGroup,看來(lái)我們的jar文件是加少了,把netty-resolver-4.1.4.Final.jar也加進(jìn)來(lái)。終于,我們前面編寫(xiě)的HttpClient能夠正常地跑起來(lái)了。經(jīng)過(guò)一番裁剪,Netty的大小大概從3.4MB減小到2.9MB。

總結(jié)一下,若不用體型巨大的netty-all jar文件,則我們需要導(dǎo)入如下的這些jar文件以編譯和運(yùn)行Netty:

netty-buffer-4.1.4.Final.jar netty-codec-4.1.4.Final.jar netty-codec-http-4.1.4.Final.jar netty-codec-http2-4.1.4.Final.jar netty-codec-socks-4.1.4.Final.jar netty-common-4.1.4.Final.jar netty-handler-4.1.4.Final.jar netty-resolver-4.1.4.Final.jar netty-transport-4.1.4.Final.jar

TODO

Netty的諸多抽象,比如Bootstrap,Channel,EventLoopGroup,Handler,codec,Buffer等諸多高級(jí)特性,以及它的NIO接口,這里都沒(méi)有涉及,線程模型也沒(méi)有仔細(xì)厘清。這里只是最最簡(jiǎn)單的一個(gè)使用范例,要把Netty很好地應(yīng)用在實(shí)際的項(xiàng)目中,還需要對(duì)Netty本身更深入的研究。

同時(shí),對(duì)Netty的裁剪可能也過(guò)于粗糙,或許還有更多的東西可以裁剪掉,以減小最終的APP的大小。

要使用Netty來(lái)支持HTTP/2也還需要做更多的事情。

但窺探到Netty的靈活強(qiáng)大,還是讓我們對(duì)這個(gè)庫(kù)充滿期待。

參考文檔

多個(gè)jar包的合并

Netty4.x中文教程系列

netty-4-user-guide

總結(jié)

以上是生活随笔為你收集整理的Netty HTTP on Android的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。