BaseActivity 模板设计模式的使用
二。模板设计模式 构建BaseActivity
1. 设计模式的定义
- 1.1 解决特定场景的问题,管理Activity--- 使用单例模式 管理避免activity混乱。
RecyclerView添加Header和Footer--- 装饰设计模式 - 1.2 有利于代码的规范,有算法的骨架,让代码更灵活
- 1.3 有利于开发,提高代码复用。
总结:玩一些套路,23种设计模式,《Header First 中文完整版 设计模式》、
2. 设计模式的示例
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
基本框架:
AbstractClass: 抽象类,定义了一套算法框架。
ConcreteClass: 具体的实现类,可以自定义一些算法。
Eg:计算机开机启动,码农的一天......
模式的使用场景:
- 多个子类有共有的方法,并且逻辑基本相同;
- 重要、复杂的算法,可以把核心算法设计成模板方法,周边的相关细节功能则由各个子类实现;
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
优点:基本的流程相似,其他流程使用父类的。
设计模式开源的网站:
https://github.com/simple-android-framework-exchange/android_design_patterns_analysis#schedule
3. Android 设计模式源码阅读
什么时候去阅读源码?带着思想去读。
- 1.为了验证某些在晚上看到的技术文章,为什么异步加载只能execute一次。
- 2.为了解决开发中的某些问题。5.0和5.0以上的效果区别,activity与AppCompatActivity的区别。
- 3.为了写一些架构性的框架:Okhttp框架,Volley 阅读大量源码,熟悉总结设计模式。
代码分为精读和泛读。
3.1 AsyncTask 异步加载(RxJava可替代),
// AsyncTask的使用
AsyncTask task = new AsyncTask<Void,Void,Void>(){
@Override
protected void onPreExecute() {
// 一调用就会执行的方法 UI 主线程
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
// 执行一些耗时的操作 连接网络获取数据,读取大型数据库 运行在Thread中
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// 执行完成返回的方法 ,UI主线程
}
};
// RXJava。AsyncTask符合模板的设计模式 非常符合
task.execute();
AsyncTask 源码:
// executeOnExecutor()
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)");
}
}
AsyncTask 为什么只能执行一次的问题
mStatus = Status.RUNNING; // 第一次进入设置为running状态。
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
AsyncTask 一开始就会调用 onPreExecute。
然后执行FutureTask(Runnable)执行run()方法 然后最终会调用 执行在子线程中
mWorker = new WorkerRunnable<Params, Result>() {
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);
}
};
由此可见doInBackground(mParams);就是运行在子线程中
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget(); // 在子线程中,通过发handler消息的方式,让其切换回主线程。
return result;
}
postResult 在线程中通过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;
}
finish会去判断有没有取消:
如果是取消了就会调用onCancelled()方法;
否则,就是onPostExecute() 执行在主线程中了。
最后总结:
execute()方法一调用就会去判断状态,如果状态不对就会抛异常,然后会把状态置为Running,
然后执行onPreExecute(), 开一个线程执行 doInBackground(),
等 doInBackground() 执行完毕之后,会利用Handler发送消息切换主线程中,
然后执行onPostExecute()方法,最后把状态置为FINISHED。
3.2 view绘制流程。
简单介绍一下View的绘制流程,后面讲这个自定义View的时候去,等内涵端子讲完我就会出一起专题来扫盲,写各种效果。
@CallSuper
public void draw(Canvas canvas) { // 绘制流程
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
// Step 1, draw the background, if needed
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);
}
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
// Setp 5.
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
// we're done...
return;
} // .....省略
drawBackground() --> onDraw() --> dispatchDraw(canvas)-->onDrawForeground(canvas);
自定义View。 如果想在onDraw中绘制效果,如果是继承ViewGroup是没有任何效果的,因为不会调用onDraw()该方法,
但是可以调用dispatchDraw(),继承子View的自定义控件不会有任何影响,会正常执行onDraw()方法。
4. 项目中,用到的模板模式
BaseActivity,
BaseSkinActivity(不重启应用的情况下,换肤)
/*
MVC模式:设置布局layout;初始化头部;初始化界面;初始化数据
*/
/**
* Added by Tom on 2024/06/25.
* 整个应用的BaseActivity,使用模板设计模式。
*/
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1.设置布局layout;
setContentView();
// 1.1 放置特定算法,子类都会用到的。
ViewUtils.inject(this);
// 2.初始化头部;
initTitle();
// 3.初始化界面;
initView();
// 4.初始化数据.
initData();
}
protected abstract void setContentView();
protected abstract void initTitle();
protected abstract void initView();
protected abstract void initData();
/**
* 把通用的代码封装进来。简化调用。
* 封装启动Activity: startActivity(MainActivity.class);
* @param clazz
*/
protected void startActivity(Class<?> clazz) {
Intent intent = new Intent(this, clazz);
startActivity(intent);
}
/**
* 简化findViewById,避免每次都 强制类型转换。
* @return
*/
protected <T extends View> T viewById(@IdRes int viewId) {
return (T) findViewById(viewId);
}
// 只能放一些通用的方法,基本上每个Activity都需要使用的方法,readDatabase最好不要放进来。
// 如果是多个地方要使用,最好使用工具类。因为会影响性能。
}
5.总结
类的加载机制,看源码,BaseDexClassLoader
下载没有阉割版的源码,或官网查看。
热修复,给应用打补丁: