欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式之----模板方法模式(AsyncTask源码解析)

程序员文章站 2022-06-17 12:02:25
...

一、定义

定义一个操作中的算法骨架,而将步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。

  1. 这里跟工厂方法模式很像,工厂方法模式的定义是:工厂方法模式去掉了工厂中的静态创建方法,定义为抽象方法,使得子工厂可以继承实现该方法,创建具体对象。我的工厂模式文章链接:工厂方法模式
  2. 工厂方法模式和模板方法模式区别:一个是把对象的创建延迟到子类,一个是把具体的逻辑延迟到子类。

二、角色

  • 抽象类:定义了算法骨架,把可以扩展的部分抽象出来,留待子类实现。
  • 具体类:继承抽象类,实现扩展算法,完成完整的算法。

类图如下: 设计模式之----模板方法模式(AsyncTask源码解析)

三、简单代码实现

3.1 场景

在app开发过程中,有保存数据的功能,保存数据分为:保存到数据库;保存到SharedPreference;xml等。

3.2 创建抽象父类

定义算法结构:声明为final,不让子类重写;定义抽象方法

/**
 * 抽象类:
 * 
 * @author rytong
 *
 */
public abstract class SaveData {

    protected static final String TAG = SaveData.class.getSimpleName();
    private String url;

    public SaveData(String url){
        this.url = url;
    }

    // 第一步 获取数据
    protected String getDataFromServer(String url){
        Log.e(TAG, "我已经从服务器获取到了数据");
        return "";
    }
    // 第二步 保存数据
    protected abstract String saveData(String data);

    // 第三步 保存到日志
    protected void writeLog(String result){
        Log.e(TAG,"result:"+result);
    }

    //对外接口,声明为final,不让子类重写
    public final void save(){
        String dataFromServer = getDataFromServer(url);
        String result = saveData(dataFromServer);
        writeLog(result);
    }
}

3.3 具体类实现

/**
 * 具体类,实现完整的逻辑
 * 
 * @author rytong
 *
 */
public class SaveDataToSqlite extends SaveData{

    public SaveDataToSqlite(String url) {
        super(url);
    }

    @Override
    protected String saveData(String data) {
        Log.e(TAG,"保存数据到数据库");
        return "数据库保存完成";
    }

}

3.4 调用者调用

String url = "www.baidu.com";
// 客户端调用
SaveData saveDataToXml = new SaveDataToXml(url);
SaveData saveDataToSqlite = new SaveDataToSqlite(url);

saveDataToXml.save();
saveDataToSqlite.save();

运行结果:

10-26 10:44:25.336: E/SaveData(12090): 我已经从服务器获取到了数据
10-26 10:44:25.336: E/SaveData(12090): 保存数据到xml
10-26 10:44:25.336: E/SaveData(12090): result:xml保存完成
10-26 10:44:25.336: E/SaveData(12090): 我已经从服务器获取到了数据
10-26 10:44:25.336: E/SaveData(12090): 保存数据到数据库
10-26 10:44:25.336: E/SaveData(12090): result:数据库保存完成

四、Android中的模板方法模式

在安卓源码中随处可见模板方法模式的应用,本例选取AsyncTask来说明。

4.1 AsyncTask创建

在创建AsyncTask的实例时,需要去重写doInBackground,其他的几个方法,在父类已有默认实现和调用顺序。

    new AsyncTask<String, String, String>() {

        @Override
        protected String doInBackground(String... params) {
            return null;
        }

    }.execute("");

4.2 AsyncTask源码中的方法调用顺序

  • onPreExecute()–>doInBackground()–>onPostExecute();
  • 另外几个方法,需要主动去调用,例如:onProgressUpdate()和onCancelled(),都需要主动去调用:publishProgress()和cancel()

4.3 具体的源码解析

4.3.1 execute方法

调用execute的时候走到下面的方法里。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

4.3.2 onPreExecute方法

当前方法是execute调用后,调用到executeOnExecutor,在该方法内部执行的。

    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    // 一些异常处理
    ...

    mStatus = Status.RUNNING;

    onPreExecute();

    mWorker.mParams = params;
    exec.execute(mFuture);

    return this;
}

4.3.3 mWorker和mFuture的初始化

这两个对象的初始化都在AsyncTask的构造方法中。mWorker是FutureTask类的构造方法传入的参数,所以,在下一步执行FutureTask的时候,实际上运行的是WorkerRunnable的call方法。见下一步

    public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //线程任务执行
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };

    mFuture = new FutureTask<Result>(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);
            }
        }
    };
}

4.3.4 doInBackground的执行

exec.execute(mFuture);该方法执行后,实际调用的事FutureTask的run方法,在内部执行了WorkerRunnable的call方法,在call方法内部执行了doInBackground。FutureTask的run方法代码如下(c.call()),执行完后set(result);结果被返回了。

    public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

4.3.5 onPostExecute方法

接着上一步,结果设置到一个成员变量里面了,找到这个成员变量使用的地方:set方法,如下:

protected void set(V v) {
    if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
        outcome = v;
        U.putOrderedInt(this, STATE, NORMAL); // final state
        finishCompletion();
    }
}

接着,查看一下,在哪儿使用了 这个对象。

private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

接着跟踪调用它的地方FutureTask的get():

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

也就是说我们的结果是调用get返回来的(貌似返回的是执行的结果,可以检查是否有异常等。)

真正的post是在WorkerRunnable的finally{}代码块中执行的(使用了Handler转到主线程处理):

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

顺藤摸瓜,找到Handler的handleMessage:

    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;
        }
    }
}

再接着在finish中找到了onPostExecute的身影:

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

至此整个流程执行完成。

五. 总结

5.1 优点

  • 把不变的行为搬到了父类,去除子类的代码冗余
  • 子类实现逻辑的某些细节,有助于扩展
  • 通过父类可以调用子类的具体实现,符合开闭原则。

5.2 缺点

每个不同的实现都要添加一个子类,会导致类增多,项目庞大。

5.3 适用场景

  • 某几个类似逻辑中使用了相同方法,造成代码重复的(抽象Activity)
  • 控制子类扩展,子类必须遵守某些逻辑(父类实现部分)

5.4 注意事项

定义算法结构的方法:声明为final,不让子类重写,避免恶意调用