Android開發--取消AsyncTask


    在Android應用開發過程中,為了防止UI線程堵塞,耗時的工作都應該另起一個后台線程來完成,其中AsyncTask就是其中的一種方式。最近在案子中需要“停止/取消”某個AsyncTask,在網上查了些資料,這里做個筆記。

    查看AsyncTask.java文件,其中有個cancel()函數,可以通過調用cancel(true)來停止正在運行的AsyncTask。

    /**
     * <p>Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when <tt>cancel</tt> is called,
     * this task should never run. If the task has already started,
     * then the <tt>mayInterruptIfRunning</tt> parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.</p>
     * 
     * <p>Calling this method will result in {@link #onCancelled(Object)} being
     * invoked on the UI thread after {@link #doInBackground(Object[])}
     * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
     * is never invoked. After invoking this method, you should check the
     * value returned by {@link #isCancelled()} periodically from
     * {@link #doInBackground(Object[])} to finish the task as early as
     * possible.</p>
     *
     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
     *        task should be interrupted; otherwise, in-progress tasks are allowed
     *        to complete.
     *
     * @return <tt>false</tt> if the task could not be cancelled,
     *         typically because it has already completed normally;
     *         <tt>true</tt> otherwise
     *
     * @see #isCancelled()
     * @see #onCancelled(Object)
     */
    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
       

   值得注意的是,調用cancel(true)函數需要注意以下幾點:

  1.當AsyncTask已經完成,或則以及被取消,亦或其他原因不能被取消,調用cancel()會失敗;

  2.如果AsyncTask還沒有開始執行,調用cancel(true)函數后,AsyncTask不會再執行;

  3.如果AsyncTask已經開始執行,參數mayInterruptIfRunning決定是否立即stop該Task;

  4.調用cancel()后,doInBackground()完成后,不再調用onPostExecute(),而是執行onCancelled();

 

  下面是一個簡單的Demo,使用兩個Button,分別用來start & stop AsyncTask。

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private static final String TAG = "AsyncTaskTest";
    private TestTask task = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn1).setOnClickListener(this);//start async task btn
        findViewById(R.id.btn2).setOnClickListener(this);//stop async task btn
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn1:
                task = new TestTask();
                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                break;
            case R.id.btn2:
                if (task != null && !task.isCancelled() && task.getStatus() == AsyncTask.Status.RUNNING) {
                    task.cancel(true);
                    task = null;
                }
                break;
        }
    }

    class TestTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            int count = 5;
            while (count > 0) {
                count--;
                if (isCancelled()) {  //通過isCancelled()判斷cancel(true)是否成功。
                    Log.d(TAG,"Cancel");
                    break;
                }
                Log.d(TAG,"Start Sleep");
                try {
                    Thread.sleep(2000);//模擬耗時操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d(TAG,"End Sleep");
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            Log.d(TAG,"onPostExecute");
            super.onPostExecute(aVoid);
        }

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


}

     當然真實案例中,在doInBackground()函數中,不像Demo中只有一個簡單的while()循環,所以可能需要多加幾個isCancelled()來結束doInBackground()中的任務。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM