8

AsyncTask を拡張するカスタム クラスに問題があります。私のアプリは Android 4.0.3 を対象としており、以下のコードは 30 人以上がテストしても問題なく動作します。ただし、次のように新しい AsyncRequest を呼び出すと、アプリがクラッシュするユーザーが 2 人います。

ユーザーストレージのテキストファイルに記録しているロガーが機能しており、AsyncRequest コンストラクターにあるエントリを記録していません。したがって、コンストラクターが呼び出される前にクラッシュが発生していると想定する必要があります。

このクラッシュが発生している 2 つのデバイスのうちの 1 つは、明らかに Android 4.0.4 を実行しています。他のデバイスが実行しているものがわからない。残念ながら、2 つのデバイスにアクセスできないため、logcat の出力を確認できません。

オブジェクトの作成によってクラッシュが発生する理由について、ご意見をいただければ幸いです。

String url = "www.google.com";

new AsyncRequest(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);

そして、ここに完全な AsyncRequest クラスがあります

public class AsyncRequest extends AsyncTask<String, String, String>{

HttpURLConnection connection;
InputStream inStream;
IApiCallback callback;
Context context_;

public AsyncRequest(IApiCallback callback, Context context) {
    // Log entry added for testing. Never gets called.
    FileLogger.getFileLogger(context).ReportInfo("Enter AsyncRequest Constructor");
    this.callback = callback;
    context_ = context;
}

@Override
protected String doInBackground(String... uri) {

    try {
        URL url = new URL(uri[0] + "?format=json");
        FileLogger.getFileLogger(context_).ReportInfo("Async Request: Sending HTTP GET to " + url);

        connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        connection.addRequestProperty("Accept-Encoding", "gzip");
        connection.addRequestProperty("Cache-Control", "no-cache");

        connection.connect();

        String encoding = connection.getContentEncoding();

        // Determine if the stream is compressed and uncompress it if needed.
        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
            inStream = new GZIPInputStream(connection.getInputStream());

        }  else {
            inStream = connection.getInputStream();
        }

        if (inStream != null) {
            // process response
            BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            return sb.toString();  

        }

    } catch (SocketTimeoutException e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: SocketTimeoutException", e);
        Log.i("AsyncRequest", "Socket Timeout occured");
    } catch (MalformedURLException e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: MalformedUrlException", e);
    } catch (IOException e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: IOException", e);
        Log.i("doInBackground:","IOException");

        if (e != null && e.getMessage() != null) {
            Log.i("doInBackground:",e.getMessage());
        }
    } catch (Exception e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: Exception", e);

    } finally {
        if (connection != null)
            connection.disconnect();
    }

    return null;
}

@Override
protected void onPostExecute(String result) {

    if (result != null) 
        FileLogger.getFileLogger(context_).ReportInfo("Async Request: Response is valid");
    else
        FileLogger.getFileLogger(context_).ReportInfo("Async Request: Invalid response");

    callback.Execute(result);
}
}

編集:以下のコメントに従って。

カスタム AsyncTask を呼び出す完全なメソッドを次に示します。AsyncTask を作成するまでのすべてのログ メッセージがログに表示されます。例外はありません。

ロギングには、AsyncRequest を作成する直前の URL 値が表示され、URL の形式はまったく正しくありません。それは私が期待しているものです。

public void GetServerInfoAsync(IApiCallback callback, Context context) throws IllegalArgumentException, Exception {

    if (callback == null)
        throw new IllegalArgumentException("callback");

    if (context == null)
        throw new IllegalArgumentException("context");

    try {
        FileLogger.getFileLogger(context).ReportInfo("Build URL");
        String url = GetApiUrl("System/Info");
        FileLogger.getFileLogger(context).ReportInfo("Finished building URL");

        if (url != null) {
            FileLogger.getFileLogger(context).ReportInfo("GetServerInfoAsync: url is " + url);
            new AsyncRequest(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
        } else {
            FileLogger.getFileLogger(context).ReportError("GetServerInfoAsync: url is null");
        }

    } catch (IllegalArgumentException iae) {
        FileLogger.getFileLogger(context).ReportException("GetServerInfoAsync: IllegalArgumentException", iae);
        throw iae;
    } catch (Exception e) {
        FileLogger.getFileLogger(context).ReportException("GetServerInfoAsync: Exception", e);
        throw e;
    }
}
4

2 に答える 2

0

まず第一に、executeOnExecutor()Api 11 より前では利用できないことに注意してください。問題は 4.0.4 デバイスにあると既に述べていますが、これを覚えておいてください。

問題が何であるかをトラブルシューティングするために私が取る手順は次のとおりです。これらすべてのReportInfo()ステートメントで、これらのいくつかをすでに実行しているかのようです。

まず、あなたの への呼び出しGetServerInfoAsyncは 内にあると思いますtry...catchよね?を使用しているため、確認していますThrow。また、URL のエラーをチェックするためのログを既に追加しています。エラーは実際に使用する前に発生するため、エラーは URL やインターネット アクセス許可では発生しません。callbackおよびへの参照を使用して AsyncTask 生成を呼び出しますcontextReportInfo()どの参照コンテキストを使用してログを追加しましたか?それらは機能しますか? したがって、コンテキストはあなたの問題ではありません。ただし、何が何でcallbackあるかを確認することはありません。null の場合はエラーをスローしますが、 を呼び出す前に何もしませんAsyncRequestReportInfo(callback.toString())それが何であるかを確認してみてください。

他のすべてが失敗した場合は、スレッド化のエラーのようです。の代わりに、AsyncTask だけを使用してみませんかexecuteOnExecutor()。複数のバックグラウンド スレッドが本当に必要ですか?

于 2013-05-21T12:55:57.507 に答える
0

すぐに戻ってこないことをお詫びします。ここには多くの問題がありました。

まず... Wolfram の提案のおかげで、例外をキャッチし、FileLogger (および別のクラス) が静的参照であり、これら 2 つのタブレットが実行時に参照を見つけることができなかったことが問題であると診断することができました。そのため、非同期メソッドから Logging を削除することになりました。

第二に、上記の変更を行った後、メインスレッドからルーパーを呼び出さなければならないという別の問題がありました。これら 2 つのタブレットは、メイン スレッドから非同期タスクを呼び出していないことが判明しました。そのため、MainLooper を使用して非同期呼び出しを新しい Handler に含める必要がありました。

于 2013-06-10T00:24:28.317 に答える