編輯:關於Android編程
private class DownloadFilesTask extends AsyncTask在幾個我們可以復寫的方法中,除了doInBackgroud方法別的都是執行在主線程中的。 當我們使用一個AsyncTask的時候我們必須指定3個泛型類型和實現doInBackground()函數。{ protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } }
public abstract class AsyncTask這是AnsyncTask需要定義的3個泛型數據。 第一個Params是我們需要指定重寫的doInBackgroud的參數
protected abstract Result doInBackground(Params... params);第二個progress是用於指定更新進度方法傳入的參數
protected void onProgressUpdate(Progress... values) { }第三個Result是用於我們指定doInBackgroun返回值和onPostExecute方法的參數
protected void onPostExecute(Result result) { }必須要實現的abstract方法doInBackgroud,就是我們需要在後台做的任務。 整個執行流程
@MainThread public final AsyncTaskexecute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);//調用另外一個execute方法,並且傳入默認的Executor } public final AsyncTask 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; }
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//AsyncTask靜態,靜態,靜態的變量 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//volatile保證多線程下數據的可見性,但是注意無法保證原子性(不理解也沒有關系) private static class SerialExecutor implements Executor { final ArrayDequesDefaultExecutor是靜態內部類SerialExecutor的一個靜態實例。這個變量是用來執行所有異步操作,我們看execute將傳入的Runnable封裝成另外一個Runnable,以便在執行run方法後執行scheduleNext()方法,並且入隊,如果沒有異步操作的話就會調用scheduleNext()方法。scheduleNext()是調用mTask中取出一個元素,放入THREAD_POOL_EXECUTOR來執行,THREAD_POOL_EXECUTOR其實是一個是一個ThreadPoolExecutor的實例,每次執行異步任務都是放入一個線程池中執行。從上面的代碼可以看出,每次線程池中只有一個線程在運行,如果當前有線程在運行的話,那麼只會將傳入的Runnable入隊,等待執行完畢後調用,並且所有的異步都是由duque來保存的所以所有任務執行順序按 。 也就是說在默認的Executor中執行異步操作,因為sDefaultExecutor是一個靜態類,所有的異步操作都是一個一個進行的,而且先後有序,我猜想這就是為什麼google建議你運行短時間的原因,如果一個異步花太多時間執行,那麼必將導致別的異步任務也將很長時間執行完成,降低體驗。mTasks = new ArrayDeque ();//雙向隊列 Runnable mActive; public synchronized void execute(final Runnable r) {//這個方法是線程安全的 mTasks.offer(new Runnable() {//將傳入的Runnable public void run() { try { r.run();//執行異步任務 } finally { scheduleNext();//當一個異步任務執行完成之後必定會調用這個方法,不管是否正常結束 } } }); if (mActive == null) {//在當前無異步執行的時候調用 scheduleNext(); } } protected synchronized void scheduleNext() {//線程安全 THREAD_POOL_EXECUTOR.execute(mActive); } } }
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//獲取虛擬機的處理器核心數 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//線程池的核心線程數 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//線程池最大線程數 private static final int KEEP_ALIVE_SECONDS = 30;//線程池超過核心線程 public static final Executor THREAD_POOL_EXECUTOR;//如果超過核心線程數空閒線程存活時間 static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(//靜態變量 CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true);//核心線程和一般線程一樣也會被殺死 THREAD_POOL_EXECUTOR = threadPoolExecutor; } 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 final WorkerRunnable可以看出mWorker是一個實現了Callable接口和可以保存mParams的一個實例。調用doInBackgroud和postResult,返回結果。mFuture將mWorker封裝成一個FutureTask對象,那麼mWorker就可以被一個實現了Executor接口的類所調用了。並且在mFuture中保證如果沒有執行Task的話調用PostResultIFNotInvoked,這個方法如果發現task沒有被執行,那麼回去調用postResult(result),用於完成onPostExecute的回調。 到現在我們可以整理下,我們調用execute(params),在調用execute線程執行onPreExecute()用默認的Executor異步執行封裝了mWorker的Future,在mWorker中執行了doInBackgroud並且將結果傳給postResult(result)。大致的流程理清楚了。那麼postResult(result)中有什麼?mWorker; private final FutureTask mFuture; public AsyncTask() { mWorker = new WorkerRunnable () { public Result call() throws Exception { mTaskInvoked.set(true);//標記任務被調用 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams);//調用回調 Binder.flushPendingCommands();// return postResult(result);//調用回調 } }; mFuture = new FutureTask (mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; } private static abstract class WorkerRunnable implements Callable { Params[] mParams; } @SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult在postResult中會直接生成一個綁定主線程的Message並且投遞給主線程,讓主線程調用finish,根據是否被取消了,調用具體的回調。publishProgress也是一樣通過向主線程投遞消息,讓主線程調用onProgressUpdate。(this, result)); message.sendToTarget(); return result; } private static Handler getHandler() {//根據單例模式獲取 synchronized (AsyncTask.class) {//對類上鎖,以防多次創建 if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } } private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override 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; } } } protected final void publishProgress(Progress... values) { if (!isCancelled()) {//發送低啊用用onprogressUpdate的回調 getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
對於觀察者,很多開發者並不陌生,在日常開發過程中,這也是一個非常常見的設計模式,尤其是Android小伙伴,很多人都知道broadcast就是一個典型的觀察者模式,還有最
本文為大家分享一個非常簡單但又很常用的控件,跑馬燈狀態的TextView。當要顯示的文本長度太長,又不想換行時用它來顯示文本,一來可以完全的顯示出文本,二來效果也挺酷,實
如今很多Android手機新品都已經預裝或可升級到Android 4.4.x版本了,而該版本最大特色就是引入了ART模式。那麼,如何才能啟動這個模式呢?AR
一、按鍵燈的簡介最近調試一下按鍵燈,今天抽空順便把的流程分析了一下。按鍵燈也是一種led,它的使用規則如命名一樣,當按鍵按下亮燈,如果一定時間不操作的話,一會會滅燈。其實