148

Handlerコードを usingから に変換していますAsyncTask。後者は、メイン UI スレッドでの非同期更新と結果の処理という点で優れています。私には不明な点は、何かがおかしくなった場合に例外を処理する方法ですAsyncTask#doInBackground

私が行う方法は、エラー Handler を用意してメッセージを送信することです。それはうまくいきますが、それは「正しい」アプローチですか、それともより良い代替手段がありますか?

また、エラー Handler を Activity フィールドとして定義すると、UI スレッドで実行する必要があることも理解しています。ただし、(非常に予想外に) 例外が発生し、トリガーされたコードがHandler#handleMessage間違ったスレッドで実行されているというメッセージが表示されることがあります。Activity#onCreate代わりにエラー Handler を初期化する必要がありますか? 配置は冗長runOnUiThreadHandler#handleMessage思えますが、非常に確実に実行されます。

4

12 に答える 12

141

AsyncResult オブジェクトを作成します (他のプロジェクトでも使用できます)。

public class AsyncTaskResult<T> {
    private T result;
    private Exception error;

    public T getResult() {
        return result;
    }

    public Exception getError() {
        return error;
    }

    public AsyncTaskResult(T result) {
        super();
        this.result = result;
    }

    public AsyncTaskResult(Exception error) {
        super();
        this.error = error;
    }
}

AsyncTask doInBackground メソッドからこのオブジェクトを返し、postExecute で確認します。(このクラスを他の非同期タスクの基本クラスとして使用できます)

以下は、Web サーバーから JSON 応答を取得するタスクのモックアップです。

AsyncTask<Object,String,AsyncTaskResult<JSONObject>> jsonLoader = new AsyncTask<Object, String, AsyncTaskResult<JSONObject>>() {

        @Override
        protected AsyncTaskResult<JSONObject> doInBackground(
                Object... params) {
            try {
                // get your JSONObject from the server
                return new AsyncTaskResult<JSONObject>(your json object);
            } catch ( Exception anyError) {
                return new AsyncTaskResult<JSONObject>(anyError);
            }
        }

        protected void onPostExecute(AsyncTaskResult<JSONObject> result) {
            if ( result.getError() != null ) {
                // error handling here
            }  else if ( isCancelled()) {
                // cancel handling here
            } else {

                JSONObject realResult = result.getResult();
                // result handling here
            }
        };

    }
于 2011-06-10T21:58:18.837 に答える
11

例外を適切に処理する必要があると感じたときは、AsyncTaskこれをスーパークラスとして使用します。

public abstract class ExceptionAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    private Exception exception=null;
    private Params[] params;

    @Override
    final protected Result doInBackground(Params... params) {
        try {
            this.params = params; 
            return doInBackground();
        }
        catch (Exception e) {
            exception = e;
            return null;
        }
    }

    abstract protected Result doInBackground() throws Exception;

    @Override
    final protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        onPostExecute(exception, result);
    }

    abstract protected void onPostExecute(Exception exception, Result result);

    public Params[] getParams() {
        return params;
    }

}

通常どおり、doInBackgroundサブクラスでオーバーライドしてバックグラウンド作業を行い、必要に応じて例外をスローします。次に、(抽象的であるため) 実装することを余儀なくされ、これにより、パラメーターとして渡されるonPostExecuteすべてのタイプの を処理するよう穏やかに思い出させられます。Exceptionほとんどの場合、例外は何らかの種類の UI 出力につながるため、それonPostExecuteを行うのに最適な場所です。

于 2013-04-29T15:37:45.393 に答える
5

他の利点をもたらす RoboGuice フレームワークを使用したい場合は、追加の Callback onException() を持つ RoboAsyncTask を試すことができます。本当にうまく機能し、私はそれを使用しています。 http://code.google.com/p/roboguice/wiki/RoboAsyncTask

于 2011-08-08T17:35:02.860 に答える
3

Cagatay Kalanのソリューションに対するより包括的なソリューションを以下に示します。

AsyncTaskResult

public class AsyncTaskResult<T> 
{
    private T result;
    private Exception error;

    public T getResult() 
    {
        return result;
    }

    public Exception getError() 
    {
        return error;
    }

    public AsyncTaskResult(T result) 
    {
        super();
        this.result = result;
    }

    public AsyncTaskResult(Exception error) {
        super();
        this.error = error;
    }
}

ExceptionHandlingAsyncTask

public abstract class ExceptionHandlingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, AsyncTaskResult<Result>>
{
    private Context context;

    public ExceptionHandlingAsyncTask(Context context)
    {
        this.context = context;
    }

    public Context getContext()
    {
        return context;
    }

    @Override
    protected AsyncTaskResult<Result> doInBackground(Params... params)
    {
        try
        {
            return new AsyncTaskResult<Result>(doInBackground2(params));
        }
        catch (Exception e)
        {
            return new AsyncTaskResult<Result>(e);
        }
    }

    @Override
    protected void onPostExecute(AsyncTaskResult<Result> result)
    {
        if (result.getError() != null)
        {
            onPostException(result.getError());
        }
        else
        {
            onPostExecute2(result.getResult());
        }
        super.onPostExecute(result);
    }

    protected abstract Result doInBackground2(Params... params);

    protected abstract void onPostExecute2(Result result);

    protected void onPostException(Exception exception)
    {
                        new AlertDialog.Builder(context).setTitle(R.string.dialog_title_generic_error).setMessage(exception.getMessage())
                .setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener()
                {
                    public void onClick(DialogInterface dialog, int which)
                    {
                        //Nothing to do
                    }
                }).show();
    }
}

タスク例

public class ExampleTask extends ExceptionHandlingAsyncTask<String, Void, Result>
{
    private ProgressDialog  dialog;

    public ExampleTask(Context ctx)
    {
        super(ctx);
        dialog = new ProgressDialog(ctx);
    }

    @Override
    protected void onPreExecute()
    {
        dialog.setMessage(getResources().getString(R.string.dialog_logging_in));
        dialog.show();
    }

    @Override
    protected Result doInBackground2(String... params)
    {
        return new Result();
    }

    @Override
    protected void onPostExecute2(Result result)
    {
        if (dialog.isShowing())
            dialog.dismiss();
        //handle result
    }

    @Override
    protected void onPostException(Exception exception)
    {
        if (dialog.isShowing())
            dialog.dismiss();
        super.onPostException(exception);
    }
}
于 2014-10-11T14:08:20.540 に答える
3

成功と失敗のコールバックを定義するインターフェイスを使用して、独自の AsyncTask サブクラスを作成しました。したがって、AsyncTask で例外がスローされた場合、onFailure 関数に例外が渡されます。それ以外の場合は、onSuccess コールバックに結果が渡されます。アンドロイドがより良いものを利用できない理由は、私にはわかりません。

public class SafeAsyncTask<inBackgroundType, progressType, resultType>
extends AsyncTask<inBackgroundType, progressType, resultType>  {
    protected Exception cancelledForEx = null;
    protected SafeAsyncTaskInterface callbackInterface;

    public interface SafeAsyncTaskInterface <cbInBackgroundType, cbResultType> {
        public Object backgroundTask(cbInBackgroundType[] params) throws Exception;
        public void onCancel(cbResultType result);
        public void onFailure(Exception ex);
        public void onSuccess(cbResultType result);
    }

    @Override
    protected void onPreExecute() {
        this.callbackInterface = (SafeAsyncTaskInterface) this;
    }

    @Override
    protected resultType doInBackground(inBackgroundType... params) {
        try {
            return (resultType) this.callbackInterface.backgroundTask(params);
        } catch (Exception ex) {
            this.cancelledForEx = ex;
            this.cancel(false);
            return null;
        }
    }

    @Override
    protected void onCancelled(resultType result) {
        if(this.cancelledForEx != null) {
            this.callbackInterface.onFailure(this.cancelledForEx);
        } else {
            this.callbackInterface.onCancel(result);
        }
    }

    @Override
    protected void onPostExecute(resultType result) {
        this.callbackInterface.onSuccess(result);
    }
}
于 2014-07-30T16:50:21.233 に答える
2

この簡単なクラスはあなたを助けることができます

public abstract class ExceptionAsyncTask<Param, Progress, Result, Except extends Throwable> extends AsyncTask<Param, Progress, Result> {
    private Except thrown;

    @SuppressWarnings("unchecked")
    @Override
    /**
     * Do not override this method, override doInBackgroundWithException instead
     */
    protected Result doInBackground(Param... params) {
        Result res = null;
        try {
            res = doInBackgroundWithException(params);
        } catch (Throwable e) {
            thrown = (Except) e;
        }
        return res;
    }

    protected abstract Result doInBackgroundWithException(Param... params) throws Except;

    @Override
    /**
     * Don not override this method, override void onPostExecute(Result result, Except exception) instead
     */
    protected void onPostExecute(Result result) {
        onPostExecute(result, thrown);
        super.onPostExecute(result);
    }

    protected abstract void onPostExecute(Result result, Except exception);
}
于 2014-01-10T13:28:42.427 に答える
2

変数メンバーの共有に依存しない別の方法は、キャンセルを使用することです。

これはアンドロイドのドキュメントからのものです:

public final boolean cancel (boolean mayInterruptIfRunning)

このタスクの実行をキャンセルしようとします。タスクが既に完了している、キャンセルされている、またはその他の理由でキャンセルできなかった場合、この試行は失敗します。成功し、キャンセルが呼び出されたときにこのタスクが開始されていない場合、このタスクは決して実行されません。タスクがすでに開始されている場合、mayInterruptIfRunning パラメータは、タスクを停止するために、このタスクを実行しているスレッドを中断する必要があるかどうかを決定します。

このメソッドを呼び出すと、doInBackground(Object[]) が戻った後、UI スレッドで onCancelled(Object) が呼び出されます。このメソッドを呼び出すと、onPostExecute(Object) が呼び出されないことが保証されます。このメソッドを呼び出した後、isCancelled() によって返される値を doInBackground(Object[]) から定期的にチェックして、できるだけ早くタスクを終了する必要があります。

したがって、catch ステートメントで cancel を呼び出し、onPostExcute が呼び出されないようにすることができますが、代わりに onCancelled が UI スレッドで呼び出されます。したがって、エラーメッセージを表示できます。

于 2013-07-24T13:22:43.133 に答える
-2

個人的には、このアプローチを使用します。情報が必要な場合は、例外をキャッチしてスタック トレースを出力できます。

バックグラウンドでのタスクがブール値を返すようにします。

こんな感じです:

    @Override
                protected Boolean doInBackground(String... params) {
                    return readXmlFromWeb(params[0]);
         }

        @Override
                protected void onPostExecute(Boolean result) {

              if(result){
              // no error
               }
              else{
                // error handling
               }
}
于 2011-01-20T05:40:02.977 に答える
-2

正しい例外がわかっている場合は、

Exception e = null;

publishProgress(int ...);

例えば:

@Override
protected Object doInBackground(final String... params) {

    // TODO Auto-generated method stub
    try {
        return mClient.call(params[0], params[1]);
    } catch(final XMLRPCException e) {

        // TODO Auto-generated catch block
        this.e = e;
        publishProgress(0);
        return null;
    }
}

「onProgressUpdate」に移動し、次のことを行います

@Override
protected void onProgressUpdate(final Integer... values) {

    // TODO Auto-generated method stub
    super.onProgressUpdate(values);
    mDialog.dismiss();
    OptionPane.showMessage(mActivity, "Connection error", e.getMessage());
}

これは、場合によってのみ役立ちます。また、Global Exception変数を保持して例外にアクセスすることもできます。

于 2012-02-04T09:40:54.280 に答える