3

私はWindowsAzureでホストされているSpring3MVCサーバーを使用しており、これを使用して、WebブラウザーとAndroidデバイスの両方を介した対話をユーザーに提供しています。すべてのコードはJavaで書かれています。

ブラウザを介してサーバーを操作する場合はすべて問題ありません。Androidを使用してサーバーを操作する場合は、サーバーがローカルホストとして実行されていれば問題なく機能します。ただし、Androidクライアントを使用してAzureでホストされているサーバーと対話すると、ランダムに(ただし常に最終的に)が取得されるNullPointerExceptionため、コードが正常に実行されることもありますが、最終的にはこれが表示されます。正確にNullPointer変更を取得しますが、それは常にを使用したHTTP呼び出し中RestTemplateです。

もう1つの奇妙なことは、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]); 呼び出しを指す

サーバー側でステートメントを入力しようとしましたが、これらNullPointerがスローされると、ステートメントに到達していないため、サーバーがリクエストを受信して​​いないように見えます。

私はこれにかなり混乱しているので、原因についての助けはNullPointerException非常にありがたいです、特にそれがうまくいくこともあればうまくいかないこともあります

編集: https://jira.springsource.org/browse/ANDROID-102のように、もう少し調べてみると、SpringforAndroidフレームワークにバグがあるようです。

これは少し役立ちますが、それでも時々機能し、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ヘッダーのuser-agentフィールドへのアクセスと設定をカスタマイズした簡単な例を次に示します。

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にアップグレードし、URLとClientHttpFactoryにロケールでString.formatを使用することを解決しました。

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 に答える