Frage

Ich konvertiere meinen Code von der Verwendung Handler zu AsyncTask. Letzteres ist großartig in dem, was es tut - asynchrone Updates und die Handhabung der Ergebnisse im Haupt UI -Thread. Was mir unklar ist, ist, wie man mit Ausnahmen umgeht, wenn etwas eingeschaltet wird AsyncTask#doInBackground.

Ich mache es, einen Fehlerhandler zu haben und Nachrichten daran zu senden. Es funktioniert gut, aber ist es der "richtige" Ansatz oder gibt es eine bessere Alternative?

Ich verstehe auch, dass, wenn ich den Fehlerhandler als Aktivitätsfeld definiere, im UI -Thread ausgeführt werden sollte. Manchmal (sehr unvorhersehbar) bekomme ich jedoch eine Ausnahme, die besagt, dass der Code ausgelöst wird Handler#handleMessage wird auf dem falschen Thread ausgeführt. Soll ich den Fehlerhandler initialisieren Activity#onCreate stattdessen? Platzierung runOnUiThread hinein Handler#handleMessage Scheint überflüssig, aber es wird sehr zuverlässig ausgeführt.

War es hilfreich?

Lösung

Es funktioniert gut, aber ist es der "richtige" Ansatz und gibt es eine bessere Alternative?

Ich halte mich fest Throwable oder Exception in dem AsyncTask Instanz selbst und dann etwas damit machen onPostExecute(), Daher hat meine Fehlerbehandlung die Möglichkeit, einen Dialog auf dem Bildschirm anzuzeigen.

Andere Tipps

Erstellen Sie ein asynchronisiertes Objekt (das Sie auch in anderen Projekten verwenden können)

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

Geben Sie dieses Objekt aus Ihren Asynctask -Doinbackground -Methoden zurück und überprüfen Sie es im Postexecute. (Sie können diese Klasse als Basisklasse für Ihre anderen asynchronen Aufgaben verwenden)

Im Folgenden finden Sie ein Modell einer Aufgabe, die eine JSON -Antwort vom Webserver erhält.

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

    }

Wenn ich das Bedürfnis habe, Ausnahmen in den Umgang mit AsyncTask Richtig, ich benutze dies als Superklasse:

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

}

Als normal überschreiben Sie doInBackground In Ihrer Unterklasse, um Hintergrundarbeit zu erledigen, werfen Sie bei Bedarf gerne Ausnahmen aus. Sie sind dann gezwungen zu implementieren onPostExecute (Weil es abstrakt ist) und dies erinnert Sie sanft daran, alle Arten von zu verarbeiten Exception, die als Parameter übergeben werden. In den meisten Fällen führen Ausnahmen zu einer Art von UI -Ausgabe, also onPostExecute ist ein perfekter Ort dafür.

Wenn Sie das Roboguice -Framework verwenden möchten, das Ihnen andere Vorteile bringt, können Sie den Roboasynctask mit einem zusätzlichen Rückruf -Onexception () ausprobieren. Funktioniert wirklich gut und ich benutze es.http://code.google.com/p/roboguice/wiki/roboasynctask

Ich habe meine eigene Asynctask -Unterklasse mit einer Schnittstelle erstellt, die Rückrufe für Erfolg und Misserfolg definiert. Wenn also eine Ausnahme in Ihr Asynctask eingelegt wird, wird die OnFailure -Funktion die Ausnahme übergeben, andernfalls wird der Onsuccess -Rückruf über Ihr Ergebnis weitergegeben. Warum Android nichts Besseres zur Verfügung hat, ist mir ein Rätsel.

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

Eine umfassendere Lösung für Cagatay KalanDie Lösung wird unten angezeigt:

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

Außerdem

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

Beispielaufgabe

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

Diese einfache Klasse kann Ihnen helfen

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

Eine andere Möglichkeit, die nicht von der Freigabe von Variablenmitgliedern abhängt, ist die Verwendung von Abbrechen.

Dies ist von Android Docs:

öffentliches Final Boolean Cancel (boolean Maiinterruptifrunning)

Versuche, die Ausführung dieser Aufgabe zu kündigen. Dieser Versuch schlägt fehl, wenn die Aufgabe bereits abgeschlossen, bereits abgesagt wurde oder aus einem anderen Grund nicht abgesagt werden kann. Wenn er erfolgreich ist und diese Aufgabe nicht begonnen hat, wenn Cancel aufgerufen wird, sollte diese Aufgabe niemals ausgeführt werden. Wenn die Aufgabe bereits gestartet wurde, bestimmt der Mai -Mai -Interruptifrunning -Parameter, ob der Thread, der diese Aufgabe ausführt, unterbrochen werden, um die Aufgabe zu stoppen.

Das Aufrufen dieser Methode führt dazu, dass auf dem UI -Thread nach DOInbackground (Object []) auf dem UI -Thread (Objekt []) aufgerufen wird. Das Aufrufen dieser Methode garantiert, dass OnPostExecute (Objekt) niemals aufgerufen wird. Nachdem Sie diese Methode aufgerufen haben, sollten Sie den von iscancelled () regelmäßigen DOInbackground (Objekt []) zurückgegebenen Wert überprüfen, um die Aufgabe so früh wie möglich zu beenden.

Sie können also die Catch -Anweisung COMING anrufen und sicher sein, dass OnPostexcute nie aufgerufen wird, sondern auf UI -Thread aufgerufen wird. Sie können also die Fehlermeldung anzeigen.

Tatsächlich verwenden Asynctask Futuretask & Executor, Futuretask Support Exception-Chain First Let Let Let Let Let Let Let Let Let Lit a Helper-Klasse

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

Zweitens, lasst uns verwenden

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

Persönlich werde ich diesen Ansatz verwenden. Sie können einfach die Ausnahmen fangen und die Stapelspur ausdrucken, wenn Sie die Informationen benötigen.

Machen Sie Ihre Aufgabe im Hintergrund einen booleschen Wert zurück.

Es ist so:

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

        @Override
                protected void onPostExecute(Boolean result) {

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

Eine andere Möglichkeit wäre zu verwenden Object als Rückkehrtyp und in onPostExecute() Überprüfen Sie den Objekttyp. Es ist kurz.

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

Wenn Sie die richtige Ausnahme kennen, können Sie das anrufen

Exception e = null;

publishProgress(int ...);

z.B:

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

und gehen Sie zu "Onprogressupdate" und machen Sie das Laub

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

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

Dies wird nur in einigen Fällen hilfreich sein. Sie können auch eine behalten Global Exception variabel und auf die Ausnahme zugreifen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top