Android的HTTP客户端选择及HttpResponseCache的使用

据Android Dalvik团队的Jesse Wilson 同学讲, 在Android系统中可以使用两种HTTP客户端来收发HTTP数据.

一个就是大名鼎鼎的Apache HTTP Client, 而另外一个就是 HttpURLConnection.

Apache HTTP Client

DefaultHttpClient 和她的兄弟 AndroidHttpClient 是用于浏览器的及具扩展性的HTTP客户端. 他们都有很多APIs. 他们的实现都很可靠并且只有很少的BUGs.

因为已经有了一票APIs的存在, 所以Dalvik团队的同学们想要改进这个客户端并且不破坏其兼容性的情况下是非常非常困难滴! 并且Android团队的同学们也并没有负责Apache HTTP Client 的开发和维护!

HTTP URL Connection

而 HttpURLConnection 就不一样了, 这家伙是通用的 轻量级的一个HTTP客户端实现,对于大多数App来说都是够用的. 这家伙功能简洁并且很容易的增强其功能.

在 Froyo 发布以前, HttpURLConnection 有一些非人让人郁闷的BUGs . 最郁闷的是, 当你在可读取的InputStream上调用 close()函数的时候会 污染连接池 (connection pool).  可以通过禁用连接池的方法还解决这个问题:

    private void disableConnectionReuseIfNecessary() {
        // HTTP connection reuse which was buggy pre-froyo
        if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
            System.setProperty("http.keepAlive", "false");
        }
    }

在Gingerbread这个版本中, Dalvik团队的同学又添加了自动压缩数据的功能. 当你调用HttpURLConnection的时候,她回自动的偷偷的添加gzip属性到请求头中,并且会自己解压返回的数据, 开发者完全不用为了处理压缩数据而增加工作量, 只要服务器支持gzip就ok啦:

Accept-Encoding: gzip

如果你发现服务器返回的压缩数据有问题,可以参考该类的doc文档来看看如何禁用该功能!

由于Content-Length返回的是压缩后的数据长度,所以使用 getContentLength() 函数得到的Buffer数据大小是不正确的哦! 你要使用从响应中一直读取字节流直到InputStream.read()函数返回-1为止.

在Gingerbread版本中,同样也增强了HTTPs的功能. HttpsURLConnection尝试和Server Name Indication (SNI)连接,这样多个HTTPs主机可以共享同一个IP地址. 同样支持压缩和session tickets. 如果连接失败,她会自动禁用这些功能去重新连接.

而在 Ice Cream Sandwich版本中,Dalvik团队的同学又不安分了, 继续添加了一些新的特性: 响应缓存(response cache) . 如果使用了缓存,那么HTTP请求会有3种情况:

  • 完全缓存的结果将直接从本地缓存中返回,省去了联网访问服务器的过程, 在中国的龟速移动网络环境中很有用哦
  • 有条件(期限)的缓存将通过服务器来判断,客户端将发送这样一个请求”如果昨天得到的/foo.png这个图片已经更新了的话,就返回给我一个新的图片”,如果服务器更新了图片就返回新的数据 如果没有更新则返回”304 Not Modified ”.对于没有更新的内容就节约了流量.
  • 对于没有缓存过的内容就直接请求服务器的数据,然后把这个结果再放到缓存中去.
如果您想在Ice Cream Sandwich版本中使用缓存这个有用的功能,而又不想在其他版本的系统中导致程序Crash 该怎么办!
这个时候Java强大的反射就再一次的挽救广大的开发者于水火之中! 代码如下:
    private void enableHttpResponseCache() {
        try {
            long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
            File httpCacheDir = new File(getCacheDir(), "http");
            Class.forName("android.net.http.HttpResponseCache")
                .getMethod("install", File.class, long.class)
                .invoke(null, httpCacheDir, httpCacheSize);
        } catch (Exception httpResponseCacheNotAvailable) {
        }
    }
如果有” android.net.http.HttpResponseCache“这个类 就使用缓存,没有就当没这回事, 该怎么滴就怎么滴了.
注意: 如果你想使用缓存, 还有配置你的服务器让她也支持缓存哦!

开发者该选择哪个客户端使用呢?

在Eclair 和 Froyo版本中, Apache HTTP Client具有更少的BUGs,所以应该在这个版本中用Apache.
而对于Gingerbread 及其以后的版本中, HttpURLConnection 是最好的选择. 其简洁的API和轻量级的实现用于Android系统再适合不过了. 对开发者透明的压缩和缓存实现,可以减少网络数据传输量, 提高程序响应速度 同时也节约设备电源.
新的App应该使用  HttpURLConnection;Dalvik团队的同学将会把他们的无聊时间继续投入到这个实现上来,从而增强其功能.
或许 到未来的某一天你发现 HttpURLConnection和Apache HTTP Client变得一样强大和复杂了 ! \(^o^)/~


之前我们在软件开发中,cache都是自己来写,不管是图片缓存还是其他从网络获取的数据,有了HttpResponseCache,它帮助我们可以很好的解决cache这个问题(我现在感觉他只适合cache一些小的数据,如果大量的图片cache还是自己缓存到SD卡上面去比较好)。

HttpResponseCache的好处:

1.明显一点节约电,减少了网络请求。

2.开发者不用自己在去写cache机制了。

3.最根本的一点就是,如果开发者在开发中不是使用的HttpClient, HttpDefaultClient..., 而是用 HttpURLConnection的话, 你根本不用改本來的 Code。

这个我们就不多说了,直接看示例:

在开发中你不用写其他任何东西,只要在Application层将其启动就好了 其他的全部交给HttpURLConnection处理就行。

[java]  view plain copy
  1. public class HttpCacheApplication extends Application {  
  2.     @Override  
  3.     public void onCreate() {  
  4.         super.onCreate();  
  5.         new Thread() {  
  6.             @Override  
  7.             public void run() {  
  8.                 enableHttpResponseCache();  
  9.             }  
  10.         }.start();  
  11.     }  
  12.   
  13.     private void enableHttpResponseCache() {  
  14.         try {  
  15.             long httpCacheSize = 10 * 1024 * 1024;// 10M  
  16.             File httpCacheDir = new File(getCacheDir(), "http");  
  17.             Class.forName("android.net.http.HttpResponseCache")  
  18.                     .getMethod("install", File.classlong.class)  
  19.                     .invoke(null, httpCacheDir, httpCacheSize);  
  20.         } catch (Exception e) {  
  21.             Log.e("===>", e.getMessage(), e);  
  22.         }  
  23.     }  
  24.   
  25. }  

接下来我们来看看HttpUrlConnection是怎么处理的,怎么缓存的。

[java]  view plain copy
  1. public class MainActivity extends Activity {  
  2.   
  3.     private final String TAG = getClass().getSimpleName();  
  4.     ImageView img;  
  5.     Button msg;  
  6.     TextView tv;  
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.   
  12.         img = (ImageView) findViewById(R.id.imageView1);  
  13.         tv = (TextView)findViewById(R.id.textView1);  
  14.         msg = (Button) findViewById(R.id.button1);  
  15.         msg.setOnClickListener(new OnClickListener() {  
  16.             @Override  
  17.             public void onClick(View v) {  
  18.                 new InternetTask().execute();  
  19.             }  
  20.         });  
  21.         findViewById(R.id.button2).setOnClickListener(new OnClickListener() {  
  22.               
  23.             @Override  
  24.             public void onClick(View v) {  
  25.                 MainActivity.this.finish();  
  26.             }  
  27.         });  
  28.     }  
  29.   
  30.     class InternetTask extends AsyncTask<String, String, Boolean> {  
  31.         Bitmap bitmap;  
  32.         String jsonStr;  
  33.   
  34.         @Override  
  35.         protected void onPostExecute(Boolean result) {  
  36.             super.onPostExecute(result);  
  37.             img.setImageBitmap(bitmap);  
  38.             tv.setText(jsonStr);  
  39.         }  
  40.   
  41.         @Override  
  42.         protected Boolean doInBackground(String... params) {  
  43.             // Test download image  
  44.             try {  
  45.                 URL url = new URL("http://news.baidu.com/resource/img/logo_news_137_46.png");  
  46.                 HttpURLConnection conn = (HttpURLConnection) (url  
  47.                         .openConnection());  
  48.                 conn.connect();  
  49.                 InputStream is = conn.getInputStream();  
  50.                 BitmapFactory.Options ops = new BitmapFactory.Options();  
  51.                 bitmap = BitmapFactory.decodeStream(is, null, ops);  
  52.                 is.close();  
  53.                 conn.disconnect();   
  54.             } catch (Exception e) {  
  55.                 Log.e(TAG, e.getMessage(), e);  
  56.             }  
  57.   
  58.             // Test download JSON data  
  59.             try {  
  60.                 URL url = new URL("http://www.baidu.com/");  
  61.                 HttpURLConnection conn = (HttpURLConnection) (url  
  62.                         .openConnection());  
  63.                 conn.connect();    
  64.                 BufferedReader reader = new BufferedReader(  
  65.                         new InputStreamReader(conn.getInputStream(), "UTF-8"));  
  66.                 jsonStr = reader.readLine();  
  67.                 InputStream is = conn.getInputStream();  
  68.                 is.close();  
  69.                 conn.disconnect();  
  70.             } catch (Exception e) {  
  71.                 Log.e(TAG, e.getMessage(), e);  
  72.             }  
  73.             return true;  
  74.         }  
  75.   
  76.     }  
  77.   
  78. }  
我们看下效果:

看下缓存文件,每个文件会产生两个文件,一个是数据文件,一个是http header 信息


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值