Android에서의 AsyncTask 및 오류 처리



Answers

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에서이 개체를 확인하십시오. (이 클래스를 다른 비동기 작업의 기본 클래스로 사용할 수 있습니다)

아래는 웹 서버에서 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
            }
        };

    }
Question

코드에서 HandlerAsyncTask 로 변환 중입니다. 후자는 비동기 업데이트 및 주요 UI 스레드에서 결과 처리와 같은 기능을 제공합니다. AsyncTask#doInBackground 에서 뭔가 잘못 될 경우 예외를 처리하는 방법이 무엇인지 AsyncTask#doInBackground .

내가하는 일은 에러 처리기를 가지고 그것에 메시지를 보내는 것이다. 그것은 잘 작동하지만 "올바른"접근인가 아니면 더 나은 대안인가?

또한 오류 처리기를 활동 필드로 정의하면 UI 스레드에서 실행되어야 함을 이해합니다. 그러나 때로는 (매우 예측할 수 없을 정도로) Handler#handleMessage 에서 트리거 된 코드가 잘못된 스레드에서 실행 중임을 알리는 예외가 발생합니다. 대신 Activity#onCreate 오류 처리기를 초기화해야합니까? runOnUiThreadHandler#handleMessage 배치하는 것은 중복 된 것처럼 보이지만 매우 안정적으로 실행됩니다.




또 다른 가능성은 Object 를 반환 유형으로 사용하고 onPostExecute() 에서 객체 유형을 확인하는 것입니다. 그것은 짧다.

class MyAsyncTask extends AsyncTask<MyInObject, Void, Object> {

    @Override
    protected AsyncTaskResult<JSONObject> doInBackground(MyInObject... myInObjects) {
        try {
            MyOutObject result;
            // ... do something that produces the result
            return result;
        } catch (Exception e) {
            return e;
        }
    }

    protected void onPostExecute(AsyncTaskResult<JSONObject> outcome) {
        if (outcome instanceof MyOutObject) {
            MyOutObject result = (MyOutObject) outcome;
            // use the result
        } else if (outcome instanceof Exception) {
            Exception e = (Exception) outcome;
            // show error message
        } else throw new IllegalStateException();
    }
}



다른 이점을 가져 오는 RoboGuice 프레임 워크를 사용하려는 경우 추가 콜백 onException ()이있는 RoboAsyncTask를 사용해 볼 수 있습니다. 진짜 좋은 작품과 나는 그것을 사용합니다. http://code.google.com/p/roboguice/wiki/RoboAsyncTask




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);
    }
}



성공과 실패에 대한 콜백을 정의하는 인터페이스로 자체 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);
    }
}





Related