문제

코드를 사용하여 변환하고 있습니다 Handler 에게 AsyncTask. 후자는 기본 UI 스레드에서 비동기 업데이트 및 결과 처리에 능숙합니다. 나에게 불분명 한 것은 무언가가 건초 와이어에 들어가면 예외를 처리하는 방법입니다. AsyncTask#doInBackground.

내가하는 방식은 오류 핸들러가 있고 메시지를 보내는 것입니다. 잘 작동하지만 "올바른"접근 방식입니까, 아니면 더 나은 대안이 있습니까?

또한 오류 핸들러를 활동 필드로 정의하면 UI 스레드에서 실행해야한다는 것을 이해합니다. 그러나 때때로 (매우 예측할 수 없을 정도로) 코드가 트리거된다는 예외를 얻을 것입니다. Handler#handleMessage 잘못된 스레드에서 실행 중입니다. 오류 처리기를 초기화해야합니까? Activity#onCreate 대신에? 자본 매출 runOnUiThread ~ 안으로 Handler#handleMessage 중복 된 것처럼 보이지만 매우 안정적으로 실행됩니다.

도움이 되었습니까?

해결책

잘 작동하지만 "올바른"접근 방식이며 더 나은 대안이 있습니까?

나는 붙잡고있다 Throwable 또는 Exception 에서 AsyncTask 인스턴스 자체를 사용하여 무언가를 수행합니다 onPostExecute(), 오류 처리에는 화면에 대화 상자를 표시 할 수있는 옵션이 있습니다.

다른 팁

비동기 객체 만들기 (다른 프로젝트에서도 사용할 수 있음)

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

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

    }

예외를 처리 할 필요성을 느낄 때 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 그렇게하기에 완벽한 장소입니다.

Roboguice 프레임 워크를 사용하려면 다른 혜택을 제공하는 다른 혜택을 제공 할 수 있습니다. 정말 잘 작동하고 사용합니다.http://code.google.com/p/roboguice/wiki/roboasynctask

성공과 실패를위한 콜백을 정의하는 인터페이스로 내 자신의 Asynctask 서브 클래스를 만들었습니다. 따라서 Asynctask에서 예외가 발생하면 Onfailure 기능이 예외가 전달됩니다. 그렇지 않으면 Onsuccess 콜백이 결과가 전달됩니다. Android가 더 나은 것을 가지고 있지 않은 이유는 저를 넘어선 것입니다.

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

보다 포괄적 인 솔루션 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;
    }
}

예외 처리장 입력

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

이 간단한 수업이 도움이 될 수 있습니다

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

가변 회원 공유에 의존하지 않는 또 다른 방법은 취소를 사용하는 것입니다.

이것은 Android 문서에서 나온 것입니다.

공개 최종 부울 취소 (부울 Mayinterruptifrunning)

이 작업의 실행을 취소하려고 시도합니다. 작업이 이미 완료되었거나 이미 취소되었거나 다른 이유로 취소 할 수없는 경우이 시도는 실패합니다. 성공하고 취소가 호출 될 때이 작업이 시작되지 않은 경우이 작업은 실행되지 않아야합니다. 작업이 이미 시작된 경우, MayinterRupRifrunning 매개 변수는이 작업을 실행하는 스레드가 작업을 중지하려는 시도에서 중단되어야하는지 여부를 결정합니다.

이 메소드를 호출하면 doinbackground (Object [])가 반환 한 후 UI 스레드에서 ancancelled (객체)가 호출됩니다. 이 방법을 호출하면 OnPostExecute (Object)가 호출되지 않도록 보장합니다. 이 메소드를 호출 한 후에는 doinbackground (Object [])에서 iscancelled ()에 의해 반환 된 값을 최대한 빨리 완료하려면 작업을 완료해야합니다.

따라서 Catch 문서에서 취소를 호출하고 OnPostExcute가 호출되지 않았는지 확인할 수 있지만 UI 스레드에서 OnCancelled가 호출됩니다. 따라서 오류 메시지를 표시 할 수 있습니다.

실제로 Asynctask는 Futuretask & Executor를 사용하여 FutureTask 지원 예외 체인 먼저 헬퍼 클래스를 정의하자

public static class AsyncFutureTask<T> extends FutureTask<T> {

    public AsyncFutureTask(@NonNull Callable<T> callable) {
        super(callable);
    }

    public AsyncFutureTask<T> execute(@NonNull Executor executor) {
        executor.execute(this);
        return this;
    }

    public AsyncFutureTask<T> execute() {
        return execute(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @Override
    protected void done() {
        super.done();
        //work done, complete or abort or any exception happen
    }
}

둘째, 사용합시다

    try {
        Log.d(TAG, new AsyncFutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //throw Exception in worker thread
                throw new Exception("TEST");
            }
        }).execute().get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        //catch the exception throw by worker thread in main thread
        e.printStackTrace();
    }

개인적으로, 나는이 접근법을 사용할 것입니다. 정보가 필요한 경우 예외를 포착하고 스택 추적을 인쇄 할 수 있습니다.

배경에서 작업을 부울 가치로 반환하십시오.

이것은 다음과 같습니다.

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

        @Override
                protected void onPostExecute(Boolean result) {

              if(result){
              // no error
               }
              else{
                // error handling
               }
}

또 다른 가능성은 사용하는 것입니다 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();
    }
}

올바른 예외를 알고 있다면

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"로 가서 Foling을 수행하십시오.

@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 변수 및 예외에 액세스하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top