2016-05-17 4 views
-1

Я реализовал способ получить результат от onPostExecute до моего основного вида деятельности. Я хотел знать, правильно ли это было, есть ли еще какие-то возможности улучшить его, и если это не лучший способ, то какой лучший способ?Лучший способ получить результат от AsyncTask до класса вызывающего абонента

Это то, что я сделал:

public class MainClass implements AsyncResponse { 
    private MyAsyncTask asyncTask; 

    public MainClass() { 
     asyncTask = new MyAsyncTask(); 
     asyncTask.asyncResponse = this; 
    } 

    public void startTask({ 
     asyncTask.execute("string"); 
    } 

    @Override 
    public void processDone(String res) { 
     // got response in MainClass from onPostExecute 
    } 

    private class MyAsyncTask extends AsyncTask<String, String, String> { 

     protected AsyncResponse asyncResponse = null; 

     @Override 
     protected String doInBackground(String... urls) { 
      return "some processed string"; 
     } 

     @Override 
     protected void onPostExecute(String res) { 
      this.asyncResponse.processDone(res); 
     } 
    } 
} 

Вот AsyncResponse интерфейс:

public interface AsyncResponse { 
    void processDone(String res); 
} 

Я хочу знать, с точки зрения скорости обработки, что в среднем андроида мобильного устройства, это было бы хороший подход, а если нет, как мне его улучшить, чтобы сделать его хорошим подходом?

Спасибо.

ответ

0

Я всегда делал это так и не имел никаких проблем. Я бы сказал, что это лучший способ.

0

в одной строке без обратного вызова

String s= new MyAsyncTask().execute().get(); 
0

Вы добавили ненужный интерфейс - и, возможно, это делает ваш код менее годным к употреблению.

Во-первых, если вы создаете AsyncTask как класс в пределах вашего Activity, нет необходимости в интерфейсе. Вы можете просто сделать это:

@Override 
protected void onPostExecute(String res) { 
    processDone(res); 
} 

AsyncTask выполнит onPostExecute в потоке пользовательского интерфейса, и вы можете вызвать метод Activity без интерфейса.

Во-вторых, если вы создаете AsyncTask вне Activity класса (например, в своем собственном файле Java), то вы можете использовать этот метод, за исключением того, что это не очень хорошая идея, потому что она будет содержать ссылку на Activity в другом потоке - это риск утечки памяти.

Чтобы избежать этого, ваш интерфейс должен быть реализован в отдельном классе, например AsyncTaskResponse.java, который передается классу AsyncTask.

Последнее, AsyncTask обеспечивает ответ в виде String, если этого достаточно. Вы должны смотреть на документы на AsyncTask:

https://developer.android.com/reference/android/os/AsyncTask.html

+0

Но я мог бы просто сделать его многоразовым, разделив класс асинтезы и использовать его в других классах. Тогда я должен был бы иметь интерфейс правильно? –

0

Вы обертывание AsyncTask внутри другого класса POJO; делать это не повредит, но приносит небольшую пользу.

Учтите, что когда задача будет завершена, вы захотите получить уведомление об обратном вызове. Ваш MainClass получит обратный вызов в processDone(), но что-то нужно будет слушать MainClass, чтобы получить это уведомление.

Вот образец, который я всегда использую с моим AsyncTask подклассов:

public class GetDataRemoteTask extends AsyncTask<String, Void, Data> { 

    private static final String TAG = "GetDataRemoteTask "; 

    private WeakReference<GetDataResultListener> mListenerRef; 

    private Exception mExc; 

    @Override 
    protected Data doInBackground(String... params) { 

     Data result = null; 

     try { 
      result = mService.getData(params[0], params[1], params[2]); 

     } catch (Exception e) { 
      Log.e(TAG, "Error occurred getting data", e); 
      mExc = e; 
     } 
     return result; 
    } 

    @Override 
    protected void onPostExecute(Data result) { 

     if (mListenerRef != null) { 
      GetDataResultListener listener = mListenerRef.get(); 
      if (listener != null) { 
       if (mExc == null) { 
        listener.dataReceived(result); 
       } else { 
        listener.dataException(mExc); 
       } 
      } 
     } 
    } 

    public void setGetDataResultListener(GetDataResultListener listener) { 

     if (listener == null) { 
      this.mListenerRef = null; 
     } else { 
      this.mListenerRef = new WeakReference<GetDataResultListener >(listener); 
     } 
    } 

    public static interface GetDataResultListener { 

     public void dataReceived(Data data); 

     public void dataException(Exception exc); 
    } 

} 

Итак, чтобы начать, здесь у меня есть интерфейс, как вы делаете, для подключения к AsyncTask.Но я не завершу свой AsyncTask реализацией, я ожидаю, что у меня будет Activity или Fragment, которые будут реализовывать этот интерфейс. (Вот почему я использую WeakReference, если заканчивается Activity, мой AsyncTask не будет удерживаться на Activity. Но это также означает, что я не могу использовать прослушиватель анонимного класса, если только клиент не держит ссылку для него.)

Мой клиент код будет выглядеть следующим образом:

 GetDataRemoteTask task = new GetDataRemoteTask(); 
     task.setListener(this); 
     task.execute(param1, param2, param3); 

у меня также есть способ узнать, есть ли исключение, которое произошло в фоновом режиме. Любые фоновые исключения всегда должны сообщаться клиенту, который может решить, как лучше всего справиться с этим исключением - например, открыть диалог для пользователя, чтобы они знали, что запрос не выполнен.

Я считаю, что большой недостаток AsyncTask заключается в том, что он не имеет больше структуры вокруг обработки исключений, которые встречаются в фоновом потоке.

В моей задаче содержится ссылка на исключение, но я также использовал Pair<Data, Exception> как параметр типа для результата возврата, поэтому мне не требуется свойство исключения.

Использование этого шаблона помогло мне избежать некоторых типичных проблем, возникающих при кодировании подклассов AsyncTask.

Смежные вопросы