Android中AsyncTask分析--你所不注意的坑,androidasynctask

來源:互聯網
上載者:User

Android中AsyncTask分析--你所不注意的坑,androidasynctask

AsyncTask,是android提供的輕量級的非同步類,可以直接繼承AsyncTask,在類中實現非同步作業,提供介面反饋當前非同步執行的程度(可以通過介面實現UI進度更新),最後反饋執行的結果給UI主線程.

本文不分析AsyncTask的使用,它的使用教程網上一搜一大堆,本文主要分析它的內部邏輯和實現,它是怎麼實現非同步,它是怎麼處理多個任務的,是並發嗎??

一、線程任務的調度

在AsyncTask內部會建立一個類相關的線程池來管理要啟動並執行任務,也就就是說當你調用了AsyncTask的execute()後,AsyncTask會把任務交給線程池,由線程池來管理建立Thread和運行Therad。

在Android4.0版本中它內部是有兩個線程池:SerialExecutor和ThreadPoolExecutor,SerialExecutor是串列的,ThreadPoolExecutor是並發的,而預設的就是SerialExecutor的,所以你一個程式中如果用了好幾個AsyncTask你就得注意了:不要忘了換成並發的線程池執行。下面示範一下,穿行的調度

1.一個簡單的例子:可以看出他是一個個執行的 代碼如下:
public class AsyncTaskDemoActivity extends Activity {      private static int ID = 0;      private static final int TASK_COUNT = 9;      private static ExecutorService SINGLE_TASK_EXECUTOR;      private static ExecutorService LIMITED_TASK_EXECUTOR;      private static ExecutorService FULL_TASK_EXECUTOR;            static {          SINGLE_TASK_EXECUTOR = (ExecutorService) Executors.newSingleThreadExecutor();          LIMITED_TASK_EXECUTOR = (ExecutorService) Executors.newFixedThreadPool(7);          FULL_TASK_EXECUTOR = (ExecutorService) Executors.newCachedThreadPool();      };            @Override      public void onCreate(Bundle icicle) {          super.onCreate(icicle);          setContentView(R.layout.asynctask_demo_activity);          String title = "AsyncTask of API " + VERSION.SDK_INT;          setTitle(title);          final ListView taskList = (ListView) findViewById(R.id.task_list);          taskList.setAdapter(new AsyncTaskAdapter(getApplication(), TASK_COUNT));      }            private class AsyncTaskAdapter extends BaseAdapter {          private Context mContext;          private LayoutInflater mFactory;          private int mTaskCount;          List<SimpleAsyncTask> mTaskList;                    public AsyncTaskAdapter(Context context, int taskCount) {              mContext = context;              mFactory = LayoutInflater.from(mContext);              mTaskCount = taskCount;              mTaskList = new ArrayList<SimpleAsyncTask>(taskCount);          }                    @Override          public int getCount() {              return mTaskCount;          }            @Override          public Object getItem(int position) {              return mTaskList.get(position);          }            @Override          public long getItemId(int position) {              return position;          }            @Override          public View getView(int position, View convertView, ViewGroup parent) {              if (convertView == null) {                  convertView = mFactory.inflate(R.layout.asynctask_demo_item, null);                  SimpleAsyncTask task = new SimpleAsyncTask((TaskItem) convertView);                  /*                  * It only supports five tasks at most. More tasks will be scheduled only after                  * first five finish. In all, the pool size of AsyncTask is 5, at any time it only                  * has 5 threads running.                  */                  task.execute();                // use AsyncTask#SERIAL_EXECUTOR is the same to #execute();  //                task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);                  // use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11)                  // but different from newer version of #execute()  //                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);                  // one by one, same to newer version of #execute()  //                task.executeOnExecutor(SINGLE_TASK_EXECUTOR);                  // execute tasks at some limit which can be customized  //                task.executeOnExecutor(LIMITED_TASK_EXECUTOR);                  // no limit to thread pool size, all tasks run simultaneously                  //task.executeOnExecutor(FULL_TASK_EXECUTOR);                                    mTaskList.add(task);              }              return convertView;          }      }            private class SimpleAsyncTask extends AsyncTask<Void, Integer, Void> {          private TaskItem mTaskItem;          private String mName;                    public SimpleAsyncTask(TaskItem item) {              mTaskItem = item;              mName = "Task #" + String.valueOf(++ID);          }                    @Override          protected Void doInBackground(Void... params) {              int prog = 1;              while (prog < 101) {                  SystemClock.sleep(100);                  publishProgress(prog);                  prog++;              }              return null;          }                    @Override          protected void onPostExecute(Void result) {          }                    @Override          protected void onPreExecute() {              mTaskItem.setTitle(mName);          }                    @Override          protected void onProgressUpdate(Integer... values) {              mTaskItem.setProgress(values[0]);          }      }  }    class TaskItem extends LinearLayout {      private TextView mTitle;      private ProgressBar mProgress;            public TaskItem(Context context, AttributeSet attrs) {          super(context, attrs);      }        public TaskItem(Context context) {          super(context);      }            public void setTitle(String title) {          if (mTitle == null) {              mTitle = (TextView) findViewById(R.id.task_name);          }          mTitle.setText(title);      }            public void setProgress(int prog) {          if (mProgress == null) {              mProgress = (ProgressBar) findViewById(R.id.task_progress);          }          mProgress.setProgress(prog);      }  }  
  2.你想要的並發執行上面的情況肯定不是你想要的,你想要的應該是這種情況:只需要修改一行代碼:
 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);  

  當然也可以換成你自己的線程池。

二、源碼分析  1.成員變數:

定義了需要用到的成員,可以根據名字就能知道幹什麼的

//生產線程的工廠private static final ThreadFactory sThreadFactory = new ThreadFactory() {        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());        }    };//存放任務的阻塞隊列    private static final BlockingQueue<Runnable> sPoolWorkQueue =            new LinkedBlockingQueue<Runnable>(10);    /**     * 可以平行的執行任務!就是並發的     * An {@link Executor} that can be used to execute tasks in parallel.     */    public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);    /**     * 線性執行的執行器     * An {@link Executor} that executes tasks one at a time in serial     * order.  This serialization is global to a particular process.     */    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();    //內部互動的handler    private static final InternalHandler sHandler = new InternalHandler();    //預設的Executor    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

定義了需要用到的成員,可以根據名字就能知道幹什麼的,另外注意都是static修飾的:

  第二行的sThreadFactory是建立線程的;

  第十行的sPoolWorkQueue阻塞隊列,存放任務的;

 第十七行是 THREAD_POOL_EXECUTOR是線程池,這個是並發執行的線程池;

 第26行是線性調度的線程池,SERIAL_EXECUTOR,執行完一個才會執行下一個;

 第28行是一個內部封裝的Handler:InternalHandler

 第30行可以看出他預設的是線性調度的線程池, Executor sDefaultExecutor = SERIAL_EXECUTOR,看到這裡你應該注意一個問題,如果程式裡有好多個AsyncTask,它們就是線性調度的,這肯定可你預想的不一樣,所以你別忘了換成並發的執行器。

2.內部Handler的使用:

2.1 自訂的InternalHandler(內部handler)

private static class InternalHandler extends Handler {        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})        @Override        //接受message的處理,可以看到根據狀態選擇是完成了,還是更新著        public void handleMessage(Message msg) {            AsyncTaskResult result = (AsyncTaskResult) msg.obj;            switch (msg.what) {                case MESSAGE_POST_RESULT:                    // There is only one result                    result.mTask.finish(result.mData[0]);                    break;                case MESSAGE_POST_PROGRESS:                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }    }

  在上邊handleMessage中,根據msg進行判斷,是完成了還是在更新;

     任務完成調用finish方法,在其中執行你定義的onPostExecute方法,

private void finish(Result result) {        if (isCancelled()) {            onCancelled(result);        } else {            onPostExecute(result);        }        mStatus = Status.FINISHED;    } 
  3.構造方法
public AsyncTask() {        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                return postResult(doInBackground(mParams));            }        };        mFuture = new FutureTask<Result>(mWorker) {            @Override            protected void done() {                try {                    final Result result = get();                    postResultIfNotInvoked(result);                } catch (InterruptedException e) {                    android.util.Log.w(LOG_TAG, e);                } catch (ExecutionException e) {                    throw new RuntimeException("An error occured while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                } catch (Throwable t) {                    throw new RuntimeException("An error occured while executing "                            + "doInBackground()", t);                }            }        };    }

構造方法中其實隱藏的資訊很多,WorkerRunnable和FutureTask;

其中WorkerRunnable繼承了Callable介面,應該是用於在未來某個線程的回調介面,在其中執行了ostResult(doInBackground(mParams));調用doInBackground並用postResult方法,把result發送到主線程。

FutureTask你看類的介紹是說控制任務的,控制任務的開始、取消等等,在這不細究,跟本文關係不大,而且我也沒看明白。

第17行有一個方法:postResultIfNotInvoked(result);根據名字可以看出來是如果沒有調用把把結果post出去,所以他應該是處理取消的任務的。

構造方法就分析到這,下一步就是execute():

看下postResult方法:代碼很少也很簡單,就是把msg發送給handler:

//用shandler把設定message,並發送。private Result postResult(Result result) {        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;    }
3.1 按照執行過程流程,執行個體化完,就可以調用execute():
//Params... 就相當於一個數組,是傳給doInBackground的參數public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }//執行邏輯public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,            Params... params) {        if (mStatus != Status.PENDING) {            switch (mStatus) {                case RUNNING:                    throw new IllegalStateException("Cannot execute task:"                            + " the task is already running.");                case FINISHED:                    throw new IllegalStateException("Cannot execute task:"                            + " the task has already been executed "                            + "(a task can be executed only once)");            }        }        //改變狀態        mStatus = Status.RUNNING;        //準備工作        onPreExecute();             mWorker.mParams = params;        exec.execute(mFuture);        return this;    } 

代碼邏輯很清晰,沒有幾行:

20行:修改了狀態;

21行:準備工作;

24行:設定參數;

25行:線程池調用執行,注意參數是mFuture。 

3.2 execute的執行邏輯

就以它定義SerialExecutor為例:

/*An {@link Executor} that executes tasks one at a time in serial     * order.  This serialization is global to a particular process.*/private static class SerialExecutor implements Executor {        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();        Runnable mActive;        public synchronized void execute(final Runnable r) {            mTasks.offer(new Runnable() {                public void run() {                    try {                        r.run();                    } finally {                        scheduleNext();                    }                }            });            if (mActive == null) {                scheduleNext();            }        }        protected synchronized void scheduleNext() {            if ((mActive = mTasks.poll()) != null) {                THREAD_POOL_EXECUTOR.execute(mActive);            }        }    }

 可以看到它的方法都是用synchronized關鍵字修飾的,而其讓他的介紹裡也說了在同一時間只有一個任務在執行。

   在裡邊調用r.run()方法,執行完了在調用下一個。按先後順序每次只運行一個

 

三、AsyncTask中非同步處理邏輯

沒有忘了前邊構造方法中的postResult(doInBackground(mParams))和postResultIfNotInvoked(result);方法吧,如果忘了翻前邊去看。這兩個方法把執行成功的和失敗的任務都包含了。

所以我們可以設想一下它是怎麼執行的:

1.在executeOnExecutor方法中給變數賦值

2.用執行器Executor另起線程執行任務

3.在Executor中一些複雜的邏輯,用FutureTask進行判斷任務是否被取消,如果沒有就調用回調介面call()方法,

4.在call()方法中調用了postResult(doInBackground(mParams));

5.postResult發送給主線程的Handler進行後續處理。

 

看的時候可以畫,會很清晰,基本邏輯就這樣,好AsyncTask就分析到這,歡迎錯誤修正。。。

 轉寄請註明出處,原文地址:http://www.cnblogs.com/jycboy/p/asynctask_1.html

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.