Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android ——對AsyncTask的理解和注意事項

Android ——對AsyncTask的理解和注意事項

編輯:關於Android編程

知識點補充1:Callable、Future、FutureTask

Callable

callable和running類似,是一個接口:

public interface Runnable {
    public abstract void run();
}

Callable是從Java 1.5開始提供的,位於java.util.concurrent包下:

public interface Callable {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

可以看到,兩者最大的區別就是Callable任務執行完畢之後可以得到任務執行結果。

Future

Future是一個接口:

public interface Future {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Future提供了三種功能:
  1)判斷任務是否完成;
  2)能夠中斷任務;
  3)能夠獲取任務執行結果。

因為Future只是一個接口,所以是無法直接用來創建對象使用的,因此就有了下面的FutureTask。

FutureTask

FutureTask類實現了RunnableFuture接口,RunnableFuture接口的實現如下:

public interface RunnableFuture extends Runnable, Future {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

可以看出RunnableFuture繼承了Runnable接口和Future接口,所以FutureTask既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值。

FutureTask提供了2個構造器:

public FutureTask(Callable callable) {
}
public FutureTask(Runnable runnable, V result) {
}

FutureTask實際上是一個任務的操作類,它並不啟動新線程,只是在自己所在線程上操作,任務的具體實現是構造FutureTask時提供的,實現自Callable接口的對象,FutureTask不知道具體的任務是什麼,它只知道如何調度任務,如:

如何啟動任務:在FutureTask的run()方法中(實現自Runnable.run()),調用Callable.call()方法來啟動任務,Callable.call()方法中是任務的具體實現;
如何取消任務:在cancel()裡,中斷執行任務的線程,記錄任務結束狀態,並調用done()方法來執行用戶實現的操作;
如何返回任務的運行結果:如果任務還在執行,則阻塞線程(使用LockSupport.park()),直到任務結束才返回結果,用戶可以通過get()方法來獲取結果,同樣當任務運行結束時,會調用done()來執行用戶實現的操作。
使用FutureTask的好處是,更輕松的對任務進行管理,而不是像Runnable那樣扔進線程後就啥也不能做了。

知識點補充2:Executor

Executor是任務執行者,它不關心是什麼任務,只關心如何執行任務。Executor是個Interface,具體如何執行任務要看怎麼實現這個接口。
java.util.concurrent.Executor中被注釋的代碼中提供了一個Executor實現的例子:

    class SerialExecutor implements Executor {
        final Queue tasks = new ArrayDeque();
        final Executor executor;
        Runnable active;

        SerialExecutor(Executor executor) {
            this.executor = executor;
        }

          @Override
        public synchronized void execute(final Runnable r) {
            tasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (active == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((active = tasks.poll()) != null) {
                executor.execute(active);
            }
        }
    }

這個實現的意思是,嚴格按照用戶提交的順序來串行的執行任務(當前任務運行結束,再運行下一個)。Android的AsyncTask就使用了這個例子。當然用戶也可以提供自己的Executor來改變AsyncTask的運行方式。

注意事項

AsyncTask提供了一種簡便的異步處理機制,但是它又同時引入了一些令人厭惡的麻煩。一旦對AsyncTask使用不當,很可能對程序的性能帶來負面影響,同時還可能導致內存洩露。

1、假設按照順序啟動20個AsyncTask,一旦其中的某個AsyncTask執行時間過長,隊列中的其他剩余AsyncTask都處於阻塞狀態,必須等到該任務執行完畢之後才能夠有機會執行下一個任務。
為了解決上面提到的線性隊列等待的問題,我們可以使用AsyncTask.executeOnExecutor()強制指定AsyncTask使用線程池並發調度任務。

2、如何才能夠真正的取消一個AsyncTask的執行呢?AsyncTaks有提供cancel()的方法,但是這個方法實際上做了什麼事情呢?線程本身並不具備中止正在執行的代碼的能力,為了能夠讓一個線程更早的被銷毀,我們需要在doInBackground()的代碼中不斷的添加程序是否被中止的判斷邏輯,如下:

<code class="hljs java">@Override
protected ArrayList<povideo> doInBackground(Void... params) {
    if (isCancelled())
        return null;
    for (int i = 0; i<mvideolistadapter.getcount();i++) ...="" code="" if="" override="" protected="" return="" void=""></mvideolistadapter.getcount();i++)></povideo></code>

一旦任務被成功中止,AsyncTask就不會繼續調用onPostExecute(),而是通過調用onCancelled()的回調方法反饋任務執行取消的結果。我們可以根據任務回調到哪個方法(是onPostExecute還是onCancelled)來決定是對UI進行正常的更新還是把對應的任務所占用的內存進行銷毀等。

3、使用AsyncTask很容易導致內存洩漏,一旦把AsyncTask寫成Activity的內部類的形式(非靜態內部類會默認持有外部類的引用)就很容易因為AsyncTask生命周期的不確定而導致Activity發生洩漏。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved