DefaultHttpClient 到 AndroidHttpClient

Posted

技术标签:

【中文标题】DefaultHttpClient 到 AndroidHttpClient【英文标题】:DefaultHttpClient to AndroidHttpClient 【发布时间】:2012-01-02 23:41:33 【问题描述】:

我的代码有问题,希望得到帮助。 我首先使用的是这段代码:

        new DefaultHttpClient().execute(new HttpGet(linkk)).getEntity().writeTo(
           new FileOutputStream(f));

它在 android 2.3 上运行良好,但在 4.0 上却不行。经过一番研究,我听说使用 AndroidHttpClient 更好,这样它可以在 4.0 和 3.1 上运行。问题是我不知道自己的代码修改是否正确,网上关于AndroidhttpClient的例子也不多。

这是我调整后的代码:

    AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
    HttpGet request = new HttpGet(linkk);   
    HttpResponse response = client.execute(request); //here is where the exception is thrown    
    response.getEntity().writeTo(new FileOutputStream(f));

这是 logcat 显示的内容:

     01-03 01:32:11.950: W/dalvikvm(17991): threadid=1: thread exiting with uncaught exception (group=0x40a2e1f8)
     01-03 01:32:11.986: E/AndroidRuntime(17991): FATAL EXCEPTION: main
     01-03 01:32:11.986: E/AndroidRuntime(17991): java.lang.RuntimeException: Unable to start activity ComponentInfocom.lacra.fbirthdays/com.lacra.fbirthdays.ListV: android.os.NetworkOnMainThreadException
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.app.ActivityThread.access$600(ActivityThread.java:123)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.os.Handler.dispatchMessage(Handler.java:99)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.os.Looper.loop(Looper.java:137)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at android.app.ActivityThread.main(ActivityThread.java:4424)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at java.lang.reflect.Method.invokeNative(Native Method)
     01-03 01:32:11.986: E/AndroidRuntime(17991):   at java.lang.reflect.Method.invoke(Method.java:511)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at dalvik.system.NativeStart.main(Native Method)
    01-03 01:32:11.986: E/AndroidRuntime(17991): Caused by: android.os.NetworkOnMainThreadException
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at java.net.InetAddress.lookupHostByName(InetAddress.java:391)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at java.net.InetAddress.getAllByNameImpl(InetAddress.java:242)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at java.net.InetAddress.getAllByName(InetAddress.java:220)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:137)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
    01-03 01:32:11.986: E/AndroidRuntime(17991):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)

【问题讨论】:

使用android推荐的解决方案:tinyurl.com/88mctoh 【参考方案1】:

StrictMode.ThreadPolicy 从 API 级别 9 开始引入,默认线程策略从 API 级别 11 开始更改,简而言之,不允许在 UI 线程上执行网络操作(包括 HttpClient 和 HttpUrlConnection)。如果你这样做,你会得到 NetworkOnMainThreadException。

这个限制可以改变,使用:

    if (android.os.Build.VERSION.SDK_INT > 9) 
      StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
      StrictMode.setThreadPolicy(policy);
    

将上述代码添加到您的主要活动的 onCreate() 方法中。

此外,始终建议将网络操作移出 UI 线程,例如,使用 AsyncTask。

希望对您有所帮助。

【讨论】:

这些政策的重点是强制实施良好的做法并确保您的应用程序运行良好。关闭政策是个坏主意。有关正确方法,请参阅 Sbossb 的答案。 @rgardler,仔细阅读答案:始终建议将网络操作移出 UI 线程,例如,使用 AsyncTask。 线程策略已更改,没有突出显示和许多消费者开发者不知道,值得指出为什么相同的代码在 GingerBread 而不是 HoneyComb 中工作的确切原因,另请注意,推荐使用 AsyncTask,但绝对不是唯一正确的方法。 @yorkw 呃……你为什么要把这个作为答案?!?寻求快速修复的初学者不会在意......他们只是将您的代码复制并粘贴到他们的项目中,当另一个糟糕的应用程序在 Android 市场上发布时,这将是您的错。 没有理由禁用StrictMode...它的存在是有原因的。 实际上我正在使用一个异步 http 库,它在后台线程中执行网络组件,但将控制权传回给调用者。此时某些调用可能会失败(但仅在某些手机上)..例如,如果我尝试关闭 UI 线程上的连接,即使它花费的时间非常短,它也会抛出该异常。如果我尝试从响应中读取数据(在响应返回之后),我偶尔也会收到该错误。【参考方案2】:

使用AsyncTask 以便网络请求不会阻塞 UI 线程。 NetworkOnMainThreadException 是从 API 版本 11 开始引入的,这就是它只显示 3.0 及更高版本的原因。

private class NetworkTask extends AsyncTask<String, Void, HttpResponse> 
    @Override
    protected HttpResponse doInBackground(String... params) 
        String link = params[0];
        HttpGet request = new HttpGet(link);
        AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
        try 
            return client.execute(request);
         catch (IOException e) 
            e.printStackTrace();
            return null;
         finally 
        client.close();
    
    

    @Override
    protected void onPostExecute(HttpResponse result) 
        //Do something with result
        if (result != null)
            result.getEntity().writeTo(new FileOutputStream(f));
    

要简单地调用这个线程,请这样做。

new NetworkTask().execute(linkk);

看看写在 Android 开发者网站上的this article。它更详细地解释了如何编写应用程序来处理线程。

【讨论】:

我已经尝试过了,它给了我一个我无法解决的错误。这是 logcat 显示的内容:01-03 15:01:46.508: E/AndroidRuntime(23161): java.lang.RuntimeException: Unable to start activity ComponentInfocom.lacra.fbirthdays/com.lacra.fbirthdays.ListV: java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0 01-03 15:36:44.121: E/AndroidRuntime(24957): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956) 我已经评论了 String link = params[0];我也包围了 client.execute(request);用try/catch

以上是关于DefaultHttpClient 到 AndroidHttpClient的主要内容,如果未能解决你的问题,请参考以下文章

Fiddler如何捕捉DefaultHttpClient的HTTP请求

DefaultHttpClient使用

DefaultHttpClient 更改响应大小?

DefaultHttpClient 类 Android 中的超时

Android 上 DefaultHttpClient 中连接和套接字超时的默认值是啥?

Android Wigets 不能使用自定义 DefaultHttpClient