3

我正在使用托管在 Windows Azure 上的 Spring 3 MVC 服务器,并使用它为用户提供通过 Web 浏览器和 Android 设备进行的交互。所有代码都是用 Java 编写的。

当我通过浏览器与服务器交互时,一切正常,当使用 Android 与服务器交互时,如果服务器作为 localhost 运行,它工作正常。但是,当我使用 Android 客户端与 Azure 托管服务器交互时,我随机(但总是最终)得到一个NullPointerException,所以有时代码运行良好但最终会出现。正是我得到NullPointer更改的地方,但它总是在 HTTP 调用期间使用RestTemplate.

另一个奇怪的事情是,在调试中运行 Android 应用程序时,代码将运行到代码中的某个任意点(仍然在RestTemplate调用时崩溃),但堆栈跟踪NullPointerException将指向之前进行的调用。

我为调用所做的一般代码类似于以下内容:

 private class ChangeDirectory extends AsyncTask< String, Void, Boolean >
{
    @Override
    protected Boolean doInBackground(String... directoryName) {

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add( new StringHttpMessageConverter() );

        String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";

        restTemplate.put(url, 
                         directoryName[0]);
        return true;
    }
}

堆栈跟踪如下所示:

09-05 11:32:05.081: E/AndroidRuntime(535): Caused by: java.lang.NullPointerException
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:62)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:46)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:476)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:438)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.RestTemplate.put(RestTemplate.java:364)
09-05 11:32:05.081: E/AndroidRuntime(535):  at com.artmaps.im.activity.HomeActivity$ChangeDirectory.doInBackground(HomeActivity.java:192)
09-05 11:32:05.081: E/AndroidRuntime(535):  at com.artmaps.im.activity.HomeActivity$ChangeDirectory.doInBackground(HomeActivity.java:1)
09-05 11:32:05.081: E/AndroidRuntime(535):  at android.os.AsyncTask$2.call(AsyncTask.java:264)
09-05 11:32:05.081: E/AndroidRuntime(535):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-05 11:32:05.081: E/AndroidRuntime(535):  ... 5 more

指向restTemplate.put(url, directoryName[0]); 调用

我试过在服务器端放入语句,当这些NullPointers 被抛出时,服务器似乎没有收到请求,因为没有达到语句。

任何有关原因的帮助NullPointerException将不胜感激,因为我对此感到非常困惑,尤其是有时它有效,有时却无效

编辑:根据https://jira.springsource.org/browse/ANDROID-102,在查看更多内容后,Android 框架的 Spring 中似乎存在一个错误

这有点帮助,但仍然不能解释为什么它有时会起作用,并且只会在与基于 Azure 的服务器交互时失败

4

4 回答 4

2

以为我会发布我发现的内容,以防其他人陷入困境。事实证明,这与我在问题编辑中发布的错误有关。

我通过删除 SpringRestTemplate调用并改为使用DefaultHttpClient来解决这个问题。

例如改变这个:

RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add( new StringHttpMessageConverter() );

    String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";

    restTemplate.put(url, 
                     directoryName[0]);
    return true;

对此:

String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";
        try {

            HttpClient client = new DefaultHttpClient();
            HttpPut putRequest = new HttpPut(url);
            putRequest.setEntity(new StringEntity(directoryName[0]));
            client.execute(putRequest);

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
于 2012-09-11T10:30:55.650 回答
1

ClientHttpRequestFactory我在实现自定义扩展时遇到了同样的问题SimpleClientHttpRequestFactory。我也会得到随机的 NullPointerExceptions。

解决方案是扩展HttpComponentsClientHttpRequestFactory而不是SimpleClientHttpRequestFactory在方法中执行必要的逻辑postProcessHttpRequest(HttpUriRequest httpRequest)

这是一个自定义HttpComponentsClientHttpRequestFactory访问和设置标题中的用户代理字段的快速示例:

public class CustomHTTPRequestFactory extends HttpComponentsClientHttpRequestFactory {

    public CustomHTTPRequestFactory() {
        super();
    }

    @Override
    protected void postProcessHttpRequest(HttpUriRequest httpRequest) {
        httpRequest.setHeader("User-Agent", "my-user-agent-string");
        super.postProcessHttpRequest(httpRequest);
    }

}
于 2012-12-07T14:17:48.980 回答
1

如果您收到此错误,则可能是您在使用 Gzip 压缩时遇到问题:这是解决方法,在 ICS 和 JB 上进行了测试,但这应该适用于任何地方:

灵感来自 http://android-developers.blogspot.fr/2011/09/androids-http-clients.html

    RestTemplate restTemplate = new RestTemplate() {
        @Override
        protected ClientHttpRequest createRequest( URI url, HttpMethod method ) throws IOException {
            ClientHttpRequest request = super.createRequest( url, method );
            HttpHeaders headers = request.getHeaders();
            headers.setAcceptEncoding( ContentCodingType.GZIP );

            return request;
        }
    };

    if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO ) {
        System.setProperty( "http.keepAlive", "false" );
    }

    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 ) {
        Ln.v( "Http cache disabled" );
    }

其中 Ln 是 RoboGuice 日志库。

于 2012-09-24T15:23:21.267 回答
0

我解决了升级到 1.0.1 Spring Framework 并使用 String.format 和Locale作为 URL 和ClientHttpFactory的问题。

private class ChangeDirectory extends AsyncTask< String, Void, Boolean >
{
    @Override
    protected Boolean doInBackground(String... directoryName) {

        RestTemplate restTemplate = new RestTemplate(true); // default converters
        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
        String url = String.format(Locale.getDefault(),"http://%s/ui/android/cloud/change_directory", Constants.DNS);

        restTemplate.put(url, directoryName[0]);
        return true;
    }
}

我希望这对你有用。

于 2013-02-07T15:03:51.857 回答