2012-07-23 23 views
1

我想在用戶單擊主頁按鈕時取消正在運行的AsyncTask(在AsyncTaskLoader中)。以下是我創建至今:無法取消AsyncTaskLoader中正在運行的AsyncTask

package cz.davidliska.android.loaders; 

import java.text.SimpleDateFormat; 
import java.util.Date; 

import android.content.Context; 
import android.os.Bundle; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.LoaderManager; 
import android.support.v4.content.AsyncTaskLoader; 
import android.support.v4.content.Loader; 
import android.util.Log; 

public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Date> { 
    private static final String TAG = "loader"; 
    private Date date; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     LoaderManager.enableDebugLogging(true); 
     getSupportLoaderManager().initLoader(0, savedInstanceState, this); 
    } 

    private static class DateLoader extends AsyncTaskLoader<Date> { 
     public static final String STATE_DATE_LOADER = "dateloader.state"; 
     private Date mDate; 

     public DateLoader(Context context, Bundle savedInstanceState) { 
      super(context); 
      if (savedInstanceState != null) { 
       long timeStamp = savedInstanceState.getLong(STATE_DATE_LOADER); 
       if (timeStamp != 0L) mDate = new Date(timeStamp); 
      } 
     } 

     @Override 
     protected void onStartLoading() { 
      Log.d(TAG, "Loader.onStartLoading()"); 
      if (mDate != null) { 
       deliverResult(mDate); 
      } else { 
       forceLoad(); 
      } 
     } 

     @Override 
     public void deliverResult(Date data) { 
      super.deliverResult(data); 
      Log.d(TAG, "Loader.deliverResult()"); 
      mDate = data; 
     } 

     @Override 
     protected void onStopLoading() { 
      super.onStopLoading(); 
      cancelLoad(); // try to cancel AsyncTask 
      Log.d(TAG, "Loader.onStopLoading()"); 
     } 


     @Override 
     protected void onForceLoad() { // overridden in AsyncTaskLoader 
      super.onForceLoad(); 
      Log.d(TAG, "Loader.onForceLoad()"); 
     } 

     @Override 
     protected void onReset() { 
      super.onReset(); 
      mDate = null; 
      Log.d(TAG, "Loader.onForceLoad()"); 
     } 

     @Override 
     public void onContentChanged() { 
      super.onContentChanged(); 
      Log.d(TAG, "Loader.onContentChanged()"); 
     } 

     @Override 
     protected void onAbandon() { 
      super.onAbandon(); 
      Log.d(TAG, "Loader.onContentChanged()"); 
     } 

     @Override 
     public Date loadInBackground() { // AsyncTaskLoader only 
      Log.d(TAG, "Loader.loadInBackground()"); 
      try { 
       // there will be some HttpClient.execute() 
       while(true) { 
        Thread.sleep(100); 
        Log.d(TAG, "Loader.loadInBackground() still running"); 
       } 

      } catch (InterruptedException e) { 
       Log.d(TAG, "Loader.loadInBackground() interupted"); 
      } 
      Log.d(TAG, "Loader.loadInBackground() finished"); 
      return new Date(); 
     } 

     @Override 
     public void onCanceled(Date data) { // AsyncTaskLoader only 
      super.onCanceled(data); 
      Log.d(TAG, "Loader.onCanceled()"); 
     } 

     @Override 
     protected Date onLoadInBackground() { // AsyncTaskLoader only 
      Log.d(TAG, "Loader.onContentChanged()"); 
      return super.onLoadInBackground(); 
     } 

     @Override 
     public void abandon() { 
      Log.d(TAG, "Loader.abandon()"); 
      super.abandon(); 
     } 

     @Override 
     public boolean cancelLoad() { 
      Log.d(TAG, "Loader.cancelLoad()"); 
      return super.cancelLoad(); 
     } 

     @Override 
     public void forceLoad() { 
      Log.d(TAG, "Loader.forceLoad()"); 
      super.forceLoad(); 
     } 

     @Override 
     public boolean isAbandoned() { 
      Log.d(TAG, "Loader.isAbandoned()"); 
      return super.isAbandoned(); 
     } 

     @Override 
     public boolean isReset() { 
      Log.d(TAG, "Loader.isReset()"); 
      return super.isReset(); 
     } 

     @Override 
     public boolean isStarted() { 
      Log.d(TAG, "Loader.isStarted()"); 
      return super.isStarted(); 
     } 

     @Override 
     public void reset() { 
      Log.d(TAG, "Loader.reset()"); 
      super.reset(); 
     } 

     @Override 
     public void stopLoading() { 
      Log.d(TAG, "Loader.stopLoading()"); 
      super.stopLoading(); 
     } 

     @Override 
     public boolean takeContentChanged() { 
      Log.d(TAG, "Loader.takeContentChanged()"); 
      return super.takeContentChanged(); 
     } 

    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     if (date != null) 
      outState.putLong(DateLoader.STATE_DATE_LOADER, date.getTime()); 
    } 

    public Loader<Date> onCreateLoader(int id, Bundle args) { 
     Log.d(TAG, "LoaderCallback.onCreateLoader()"); 
     if (args != null) Log.d(TAG, "bundle: " + args.getLong(DateLoader.STATE_DATE_LOADER)); 
     return new DateLoader(this, args); 
    } 

    public void onLoadFinished(Loader<Date> loader, Date data) { 
     Log.d(TAG, "LoaderCallback.onLoadFinished(): " + new SimpleDateFormat("dd/MM/yyyy").format(data)); 
     date = data; 
    } 

    public void onLoaderReset(Loader<Date> loader) { 
     Log.d(TAG, "LoaderCallback.onLoaderReset()"); 
    } 
} 

所以在onStopLoading()我打電話cancelLoad(),我認爲應該取消當前的任務,但的AsyncTask在AsyncTaskLoader仍在運行(而在loadInBackground循環()是仍在進行中)。

問題是,也許在cancelLoad()在 「java.android.support.v4.content.AsyncTaskLoader.java」 的方法,其中mTask.cancel(布爾)在辯論中被稱爲與 「假」:

public boolean cancelLoad() { 
    ... 
    boolean cancelled = mTask.cancel(false); 

有沒有機會取消在AsyncTaskLoader中運行AsyncTask?

+0

try boolean cancelled = mTask.cancel(true); – rajpara 2012-07-23 12:34:38

+0

不幸的是,mTask在AsyncTaskLoader中不可見 – 2012-07-23 13:15:39

回答

1
public boolean cancelLoad() { 
    ... 
    boolean cancelled = mTask.cancel(false); 
} 



     @Override 
     public Date loadInBackground() { // AsyncTaskLoader only 
      Log.d(TAG, "Loader.loadInBackground()"); 

      try { 
       // there will be some HttpClient.execute() 
       while(true) { 
        Thread.sleep(100); 
        Log.d(TAG, "Loader.loadInBackground() still running"); 

        if(cancelled)     <--------- 
         return new Date();   <---------- 
       } 

      } catch (InterruptedException e) { 
       Log.d(TAG, "Loader.loadInBackground() interupted"); 
      } 
      Log.d(TAG, "Loader.loadInBackground() finished"); 
      return new Date(); 
     } 
+3

這將適用於while循環,但不適用於長時間運行的操作,如執行HTTP請求。 – 2012-07-23 12:33:23

+0

在你的代碼中,我沒有找到任何http請求...! – MAC 2012-07-23 13:02:43

+0

「while循環」之上的一行是註釋//將會有一些HttpClient.execute() – 2012-07-23 13:13:28

3

如果您的意思是「是否有機會取消在android.content.AsyncTaskLoader中運行AsyncTask?」答案是肯定的:您只需要在loadInBackground方法中添加一些「取消點」並檢查是否發出取消請求(isLoadInBackgroundCanceled()== true),然後返回或拋出一個OperationCanceledException)。

AsyncTaskLoader支持庫版本使用的是雖然似乎並沒有完全實現消除在這個時候(不是至少在飛行途中,和框架和裝載機的支持版本粗略比較似乎建議取消可能根本不支持...)。

http://developer.android.com/reference/android/content/Loader.html http://developer.android.com/reference/android/support/v4/content/Loader.html

兩種方式來緩解這個問題,我想起:

  • 創建裝載機的兩種實現(一個使用API​​級別11及以上的框架,以及一個沒有取消舊設備的功能)
  • 創建一個android.support.v4.content.Loader子類並自己處理每個AsyncTask和取消請求