2012-04-01 30 views
129

我有以下asynctask類不在活動內。在活動中,我正在初始化asynctask,並且我希望asyncTask將回調報告回我的活動。 這可能嗎?或者,asynctask必須與活動在同一個類文件中?android asynctask發送回調給UI

protected void onProgressUpdate(Integer... values) 
{ 
    super.onProgressUpdate(values); 
    caller.sometextfield.setText("bla"); 
} 

是這樣的嗎?

回答

365

您可以創建一個interface,它傳遞給AsyncTask(在構造函數),然後調用方法onPostExecute()

例如:

你的接口:

public interface OnTaskCompleted{ 
    void onTaskCompleted(); 
} 

你的活動:

public class YourActivity implements OnTaskCompleted{ 
    // your Activity 
} 

An d您的AsyncTask:

public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object to required type 
    private OnTaskCompleted listener; 

    public YourTask(OnTaskCompleted listener){ 
     this.listener=listener; 
    } 

    // required methods 

    protected void onPostExecute(Object o){ 
     // your stuff 
     listener.onTaskCompleted(); 
    } 
} 

編輯

由於這個答案變得十分流行,我想添加一些東西。

如果您是Android開發人員的新手,AsyncTask是一種快速生成工作而不會阻塞UI線程的方式。它確實解決了一些問題,班級的工作方式並沒有錯。但是,它帶來一些暗示,如:

  • 內存泄漏的可能性。如果您繼續參考Activity,即使在用戶離開屏幕(或旋轉設備)後,它仍會保留在內存中。
  • AsyncTask如果Activity已被銷燬,則不會向Activity發送結果。你必須添加額外的代碼來管理所有這些東西,或者做兩次操作。
  • 費解的代碼。當你覺得你成熟到能與Android移動上,看看this article我認爲它,它確實在Activity

的一切,是一個更好的方式去開發Android應用與異步操作。

+0

應該在清單文件中寫入asyntask類嗎? – 2012-04-01 11:44:47

+1

@AsafNevo不,不應該 – 2012-04-01 11:58:49

+0

@Dmitry,除了onTaskCompleted以外,還有什麼其他的監聽器狀態?那麼onPreExecute呢? – rxlky 2013-03-24 00:14:46

6

在完成上述回答後,您還可以爲每次異步調用定製回退,以便對通用ASYNC方法的每次調用都會填充不同的數據,具體取決於您放置的onTaskDone內容。

Main.FragmentCallback FC= new Main.FragmentCallback(){ 
      @Override 
      public void onTaskDone(String results) { 

       localText.setText(results); //example TextView 
      } 
     }; 

new API_CALL(this.getApplicationContext(), "GET",FC).execute("&Books=" + Main.Books + "&args=" + profile_id); 

提醒:我用的主要活動多數民衆贊成在 「主」 說到界面,就像這樣:

public interface FragmentCallback { 
    public void onTaskDone(String results); 


} 

我的API後執行這個樣子的:

@Override 
    protected void onPostExecute(String results) { 

     Log.i("TASK Result", results); 
     mFragmentCallback.onTaskDone(results); 

    } 

的API構造器看起來像這樣:

class API_CALL extends AsyncTask<String,Void,String> { 

    private Main.FragmentCallback mFragmentCallback; 
    private Context act; 
    private String method; 


    public API_CALL(Context ctx, String api_method,Main.FragmentCallback fragmentCallback) { 
     act=ctx; 
     method=api_method; 
     mFragmentCallback = fragmentCallback; 


    } 
+3

想法很好,但要小心使用'Main.FragmentCallback'的匿名實現 - 它可能會泄漏'Activity',考慮使用'WeakReference' – 2014-06-20 07:47:47

+0

正是爲什麼這個問題被問到以上答案的機器人如果活動被破壞,而Asynctask作爲其匿名內部類別運行時有泄漏活動暗含參考 – user1530779 2015-07-07 08:07:32

37

我覺得下面的方法很簡單。

我已宣佈爲回調

public interface AsyncResponse { 
    void processFinish(Object output); 
} 

然後創建異步任務的接口,用於響應所有類型的並行請求

public class MyAsyncTask extends AsyncTask<Object, Object, Object> { 

    public AsyncResponse delegate = null;//Call back interface 

    public MyAsyncTask(AsyncResponse asyncResponse) { 
     delegate = asyncResponse;//Assigning call back interfacethrough constructor 
    } 

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

    //My Background tasks are written here 

     return {resutl Object} 

    } 

    @Override 
    protected void onPostExecute(Object result) { 
     delegate.processFinish(result); 
    } 

} 

然後點擊活動類的按鈕時調用的異步任務的。

public class MainActivity extends Activity { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     Button mbtnPress = (Button) findViewById(R.id.btnPress); 

     mbtnPress.setOnClickListener(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 

       MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() { 

        @Override 
        public void processFinish(Object output) { 
         Log.d("Response From Asynchronous task:", (String) output);   
         mbtnPress.setText((String) output); 
        } 
       }); 
       asyncTask.execute(new Object[] { "Youe request to aynchronous task class is giving here.." }); 

      } 
     }); 
    } 
} 

感謝

+0

內存泄漏情況 – user1530779 2015-07-07 08:07:54

+0

我一直在尋找確切的解決方案,並找到了這個線程,但我不明白背後的原因以上全部。在這種情況下,asynctask在MainActivity中執行,其中訪問UI不是問題。通過更新asynctask的onPostExecute()方法中的UI,可以實現同樣的效果,而無需使用特殊的接口。要解決的問題是從另一個非活動類發起異步任務,並從那裏更新UI。 – 2015-07-17 05:09:30

+0

跟你一樣..這是像我這樣的初學者的最佳答案] – 707 2016-11-13 11:37:08

2

我會重複別人說了什麼,而只是試圖使其更簡單...

首先,剛剛創建的接口類

public interface PostTaskListener<K> { 
    // K is the type of the result object of the async task 
    void onPostTask(K result); 
} 

二,通過包含具體類來創建使用接口的AsyncTask(可以是您的活動或片段的內部靜態類)。在該示例中,PostTaskListener使用String參數化,這意味着它需要一個String類作爲異步任務的結果。

public static class LoadData extends AsyncTask<Void, Void, String> { 

    private PostTaskListener<String> postTaskListener; 

    protected LoadData(PostTaskListener<String> postTaskListener){ 
     this.postTaskListener = postTaskListener; 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     super.onPostExecute(result); 

     if (result != null && postTaskListener != null) 
      postTaskListener.onPostTask(result); 
    } 
} 

最後,你的邏輯結合起來的部分。在您的活動/片段中,創建PostTaskListener並將其傳遞給異步任務。這裏是一個例子:

... 
PostTaskListener<String> postTaskListener = new PostTaskListener<String>() { 
    @Override 
    public void onPostTask(String result) { 
     //Your post execution task code 
    } 
} 

// Create the async task and pass it the post task listener. 
new LoadData(postTaskListener); 

完成!