編輯:關於Android編程
定義一個操作中的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
1、多個子類有公有的方法,並且邏輯基本相同時。
2、重要、復雜的算法,可以把核心算法設計為模板方法,周邊的相關細節功能則由各個子類實現。
3、重構時,模板方法模式是一個經常使用的模式,把相同的代碼抽取到父類中,然後通過鉤子函數約束其行為。
AbstractClass : 抽象類,定義了一套算法框架。
ConcreteClass1 : 具體實現類1;
ConcreteClass2: 具體實現類2;
模板方法實際上是封裝一個算法框架,就像是一套模板一樣。而子類可以有不同的算法實現,在框架不被修改的情況下實現算法的替換。下面我們以開電腦這個動作來簡單演示一下模板方法。開電腦的整個過程都是相對穩定的,首先打開電腦電源,電腦檢測自身狀態沒有問題時將進入操作系統,對用戶進行驗證之後即可登錄電腦,下面我們使用模板方法來模擬一下這個過程。
package com.dp.example.templatemethod; /** * 抽象的Computer * @author mrsimple * */ public abstract class AbstractComputer { protected void powerOn() { System.out.println("開啟電源"); } protected void checkHardware() { System.out.println("硬件檢查"); } protected void loadOS() { System.out.println("載入操作系統"); } protected void login() { System.out.println("小白的電腦無驗證,直接進入系統"); } /** * 啟動電腦方法, 步驟固定為開啟電源、系統檢查、加載操作系統、用戶登錄。該方法為final, 防止算法框架被覆寫. */ public final void startUp() { System.out.println("------ 開機 START ------"); powerOn(); checkHardware(); loadOS(); login(); System.out.println("------ 開機 END ------"); } } package com.dp.example.templatemethod; /** * 碼農的計算機 * * @author mrsimple */ public class CoderComputer extends AbstractComputer { @Override protected void login() { System.out.println("碼農只需要進行用戶和密碼驗證就可以了"); } } package com.dp.example.templatemethod; /** * 軍用計算機 * * @author mrsimple */ public class MilitaryComputer extends AbstractComputer { @Override protected void checkHardware() { super.checkHardware(); System.out.println("檢查硬件防火牆"); } @Override protected void login() { System.out.println("進行指紋之別等復雜的用戶驗證"); } } package com.dp.example.templatemethod; public class Test { public static void main(String[] args) { AbstractComputer comp = new CoderComputer(); comp.startUp(); comp = new MilitaryComputer(); comp.startUp(); } }
------ 開機 START ------ 開啟電源 硬件檢查 載入操作系統 碼農只需要進行用戶和密碼驗證就可以了 ------ 開機 END ------ ------ 開機 START ------ 開啟電源 硬件檢查 檢查硬件防火牆 載入操作系統 進行指紋之別等復雜的用戶驗證 ------ 開機 END ------
在Android中,使用了模板方法且為我們熟知的一個典型類就是AsyncTask了,關於AsyncTask的更詳細的分析請移步Android中AsyncTask的使用與源碼分析,我們這裡只分析在該類中使用的模板方法模式。
在使用AsyncTask時,我們都有知道耗時的方法要放在doInBackground(Params... params)中,在doInBackground之前如果還想做一些類似初始化的操作可以寫在onPreExecute方法中,當doInBackground方法執行完成後,會執行onPostExecute方法,而我們只需要構建AsyncTask對象,然後執行execute方法即可。我們可以看到,它整個執行過程其實是一個框架,具體的實現都需要子類來完成。而且它執行的算法框架是固定的,調用execute後會依次執行onPreExecute,doInBackground,onPostExecute,當然你也可以通過onProgressUpdate來更新進度。我們可以簡單的理解為如下圖的模式 :
下面我們看源碼,首先我們看執行異步任務的入口, 即execute方法 :
public final AsyncTask可以看到execute方法(為final類型的方法)調用了executeOnExecutor方法,在該方法中會判斷該任務的狀態,如果不是PENDING狀態則拋出異常,這也解釋了為什麼AsyncTask只能被執行一次,因此如果該任務已經被執行過的話那麼它的狀態就會變成FINISHED。繼續往下看,我們看到在executeOnExecutor方法中首先執行了onPreExecute方法,並且該方法執行在UI線程。然後將params參數傳遞給了mWorker對象的mParams字段,然後執行了exec.execute(mFuture)方法。execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } 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; }
mWorker和mFuture又是什麼呢?其實mWorker只是實現了Callable接口,並添加了一個參數數組字段,關於Callable和FutureTask的資料請參考Java中的Runnable、Callable、Future、FutureTask的區別與示例,我們挨個來分析吧,跟蹤代碼我們可以看到,這兩個字段都是在構造函數中初始化,
public AsyncTask() { mWorker = new WorkerRunnable簡單的說就是mFuture就包裝了這個mWorker對象,會調用mWorker對象的call方法,並且將之返回給調用者。() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return postResult(doInBackground(mParams)); } }; mFuture = new FutureTask (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); } } }; }
關於AsyncTask的更詳細的分析請移步Android中AsyncTask的使用與源碼分析,我們這裡只分析模板方法模式。總之,call方法會在子線程中調用,而在call方法中又調用了doInBackground方法,因此doInBackground會執行在子線程。doInBackground會返回結果,最終通過postResult投遞給UI線程。
我們再看看postResult的實現 :
private Result postResult(Result result) { Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; } private static class InternalHandler extends Handler { @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; } } } private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
@SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }可以看到mTask就是AsyncTask對象,調用AsyncTask對象的finish方法時又調用了onPostExecute,這個時候整個執行過程就完成了。
總之,execute方法內部封裝了onPreExecute, doInBackground, onPostExecute這個算法框架,用戶可以根據自己的需求來在覆寫這幾個方法,使得用戶可以很方便的使用異步任務來完成耗時操作,又可以通過onPostExecute來完成更新UI線程的工作。
之前自己的編程完全是在PC上進行的,而且主要是在算法和數據結構上。由於某些需要加之認識到Android的重要性,且大學走到現在基本上沒什麼課了,空閒時間很多,於是就開始學
今天面試的時候,面試官和我說起同步和異步,因為說起同步我就是想到線程同步,然後共享臨界資源啊死鎖啊什麼的,所以一直在說這個,線程異步倒是從來沒聽過。剛才看了場球想起這件事
有時候作為非官方開發的APP集成了官方的所有信息,但是現在需要實現另一個功能那就是登錄發表評論到官方的網站,而非官方的APP並不知道官方網站是怎麼實現登錄與評論的,而且越
本案例知識是:後台執行定時任務。Alarm機制:一、創建LongRunningService類 package com.example.servicebestp