关于Java:在Android中导入更新的Apache HttpClient jar

Importing a newer Apache HttpClient jar in Android

我正在尝试从我的Android客户端发送HTTP / HTTPS发布请求。

为什么我的代码失败?

至今

我创建了一个apache class / HttpClient调用。 一切正常:

1
HttpClient httpClient = new DefaultHttpClient();

我已经阅读过此方法已被弃用,因此我已切换到新的推荐方法:

1
HttpClient httpClient = HttpClientBuilder.create().build();

Eclipse没有此类,因此我必须下载Apache HttpClient 4.3.3。 我通过将其复制到libs文件夹并将其添加到我的构建路径(导入的httpclient,httpclient-cache,httpcore,httpmime,fluent-hc,commons-logging,commons-codec)将其导入到项目中。

错误信息

1
2
06-05 02:15:26.946: W/dalvikvm(29587): Link of class 'Lorg/apache/http/impl/conn/PoolingHttpClientConnectionManager;' failed
06-05 02:15:26.946: E/dalvikvm(29587): Could not find class 'org.apache.http.impl.conn.PoolingHttpClientConnectionManager', referenced from method org.apache.http.impl.client.HttpClientBuilder.build

最新代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static private String insertJson(String json,String url){
    HttpClient httpClient = HttpClientBuilder.create().build();

    String responseString ="";
    try {
        HttpPost request = new HttpPost(url);
        StringEntity params =new StringEntity(json,"UTF-8");
        request.addHeader("content-type","application/json");
        request.setEntity(params);
        HttpResponse response = httpClient.execute(request);
        HttpEntity entity = response.getEntity();
        responseString = EntityUtils.toString(entity,"UTF-8");

    }catch (Exception ex) {
        ex.printStackTrace();
        // handle exception here
    } finally {
        httpClient.getConnectionManager().shutdown();
    }
    return responseString;
}


问题在于,Android已经包含了Apache HttpClient的旧版本(目前尚不清楚哪个版本,但大约是4.0beta2)。

当您将新版本的jar添加为应用程序的库时,在加载APK时会忽略重复的类。由于HttpClient中的某些新类依赖于对这些其他类所做的修改,因此dalvik会尽其所能(例如,删除引用和&c),但是除非有条件地使用它们,否则可能会导致崩溃。

例如,您可以在logcat中看到以下消息:

1
2
3
4
06-05 00:46:39.083: I/dalvikvm(6286): Could not find method org.apache.http.client.protocol.RequestDefaultHeaders.<init>, referenced from method org.apache.http.impl.client.HttpClientBuilder.build
06-05 00:46:39.083: W/dalvikvm(6286): VFY: unable to resolve direct method 22794: Lorg/apache/http/client/protocol/RequestDefaultHeaders;.<init> (Ljava/util/Collection;)V
06-05 00:46:40.434: D/dalvikvm(6286): DexOpt: couldn't find static field Lorg/apache/http/impl/client/DefaultHttpRequestRetryHandler;.INSTANCE
06-05 00:46:40.434: W/dalvikvm(6286): VFY: unable to resolve static field 8420 (INSTANCE) in Lorg/apache/http/impl/client/DefaultHttpRequestRetryHandler;

该特定消息是因为DefaultHttpRequestRetryHandler在4.3中具有新的INSTANCE静态字段,而在Android中则没有。还有更多。

回到最初的问题,使用较新的httpclient的唯一方法是重命名所有类,这样就不会发生名称冲突。这就是httpclientandroidlib所做的。

更进一步:DefaultHttpClient在4.3中确实已被弃用,但在Android中并没有弃用(除非您认为使用HttpUrlConnection的趋势是一种不受欢迎的弃用形式-在这种情况下,较新的HttpClient也不是首选的替代方法) )。为什么您要/需要更改它呢?


一年的答案,正确的答案是使用使用不同名称空间的apache库的官方android端口,从而避免冲突:https://hc.apache.org/httpcomponents-client-4.5.x/android-port.html