一线大厂大型 APP 性能优化系列 - 自定义启动器(三),整理出 Android 逆向系列学习进阶视频
Runnable getTailRunnable();
/**
Task 执行过程中的回调*/void setTaskCallBack(TaskCallBack callBack);}
好了,这些基本够用了。
2.实现 task 接口
public abstract class Task implements ITask {
private volatile boolean mIsWaiting; // 是否正在等待 private volatile boolean mIsRunning; // 是否正在执行 private volatile boolean mIsFinished; // Task 是否执行完成 private volatile boolean mIsSend; // Task 是否已经被分发
// 当前 Task 依赖的 Task 数量(需要等待被依赖的 Task 执行完毕才能执行自己),默认没有依赖 private CountDownLatch mDepends = new CountDownLatch(dependsOn() == null ? 0 : dependsOn().size());
/**
依赖的 Task 执行完一个*/public void satisfy() {mDepends.countDown();}
/**
当前 Task 等待,让依赖的 Task 先执行*/public void waitToSatisfy() {try {mDepends.await();} catch (InterruptedException e) {e.printStackTrace();}}
/**
异步线程执行的 Task 是否需要在被调用 await 的时候等待(也就是是否需要主线程等你执行完再执行),默认不需要
@return*/@Overridepublic boolean needWait() {return false;}
/**
当前 Task 依赖的 Task 集合(需要等待被依赖的 Task 执行完毕才能执行自己),默认没有依赖
@return*/@Overridepublic List<Class<? extends Task>> dependsOn() {return null;}}
很简单,主要做的是:1.根据 dependsOn() 定义一个栅栏
很好理解,传入的 task(我们的耗时任务),因为
需要依赖,比如 TaskA,必须得等 TaskB,TaskC 加载完毕才能加载 TaskA,那么 dependsOn()返回的就是 TaskB,TaskC,也就是在 TaskA 中加了几个同步锁(锁的数量就是 TaskA 所需要依赖的 Task 数量),每次执行 satisfy()就减少一把锁。
3.实现启动器
外部调用
TaskDispatcher instance = TaskDispatcher.createInstance();instance.addTask(new InitBuglyTask()) // 默认添加,并发处理.addTask(new InitBaiduMapTask()) // 在这里需要先处理了另外一个耗时任务 initShareSDK,才能再处理它.addTask(new InitJPushTask()) // 等待主线程处理完毕,再进行执行.start();instance.await();
构建启动器
public class TaskDispatcher {
private static Context mContext;private static boolean sHasInit;private static boolean sIsMainProcess;
// 存放依赖 private HashMap<Class<? extends Task>, ArrayList<Task>> mDependedHashMap = new HashMap<>();
// 存放所有的 taskprivate List<Task> mAllTasks = new ArrayList<>();private List<Class<? extends Task>> mClsAllTasks = new ArrayList<>();
// 调用了 await 的时候还没结束的且需要等待的 Task 队列 private List<Task> mNeedWaitTasks = new ArrayList<>();
// 已经结束了的 Task 队列 private volatile List<Class<? extends Task>> mFinishedTasks = new ArrayList<>(100);
// 需要在主线程中执行的 Task 队列 private volatile List<Task> mMainThreadTasks = new ArrayList<>();
// 保存需要 Wait 的 Task 的数量 private AtomicInteger mNeedWaitCount = new AtomicInteger();private CountDownLatch mCountDownLatch;
/**
注意:每次获取的都是新对象*/public static TaskDispatcher getInstance(Context context) {
if (context != null) {mContext = context;sHasInit = true;sIsMainProcess = Utils.isMainProcess(mContext);}return new TaskDispatcher();}
/**
添加任务*/public TaskDispatcher addTask(Task task) {
if (task != null) {
// ->> 1collectDepends(task);
// ->> 2mAllTasks.add(task);mClsAllTasks.add(task.getClass());// ->> 3if (ifNeedWait(task)) {mNeedWaitTasks.add(task);mNeedWaitCount.getAndIncrement();}}return this;}
/**
存放相关依赖信息
*/private void collectDepends(Task task) {
// 如果存在依赖 if (task.dependsOn() != null && task.dependsOn().size() > 0) {
// 获取依赖 for (Class<? extends Task> cls : task.dependsOn()) {if (mDependedHashMap.get(cls) == null) {mDependedHashMap.put(cls, new ArrayList<Task>());}mDependedHashMap.get(cls).add(task);if (mFinishedTasks.contains(cls)) {task.satisfy();}}}}
/**
task 是否需要主线程等其完成再执行
*/private boolean ifNeedWait(Task task) {return !task.runOnMainThread() && task.needWait();}
@UiThreadpublic void start() {
if (Looper.getMainLooper() != Looper.myLooper()) {throw new RuntimeException("小子,启动器必须要在主线程启动");}if (mAllTasks.size() > 0) {
// 4.->> 查看被依赖的信息 printDependedMsg();
// 5.->> 拓扑排序并返回 mAllTasks = TaskSortUtil.getSortResult(mAllTasks, mClsAllTasks);
// 6.->> 构建同步锁 mCountDownLatch = new CountDownLatch(mNeedWaitCount.get());
// 7.->> 分发 taskdispatchTasks();executeTaskMain();}}
/**
查看被依赖的信息*/private void printDependedMsg() {DispatcherLog.i("needWait size : " + (mNeedWaitCount.get()));if (false) {for (Class<? extends Task> cls : mDependedHashMap.keySet()) {DispatcherLog.i("cls " + cls.getSimpleName() + " " + mDependedHashMap.get(cls).size());for (Task task : mDependedHashMap.get(cls)) {DispatcherLog.i("cls " + task.getClass().getSimpleName());}}}}
/**
task 分发,根据设定的不同规则,分发到不同的线程*/private void dispatchTasks() {for (Task task : mAllTasks) {
if (task.runOnMainThread()) {mMainThreadTasks.add(task);
if (task.needCall()) {task.setTaskCallBack(new TaskCallBack() {@Overridepublic void call() {
TaskStat.markTaskDone();task.setFinished(true);satisfyChildren(task);markTaskDone(task);}});}} else {// 异步线程中执行,是否执行取决于具体线程池 Future future = task.runOn().submit(new DispatchRunnable(task,this));mFutures.add(future);}}
/**
从等待队列中移除,添加进结束队列*/public void markTaskDone(Task task) {
// 8 ->>if (ifNeedWait(task)) {mFinishedTasks.add(task.getClass());mNeedWaitTasks.remove(task);mCountDownLatch.countDown();mNeedWaitCount.getAndDecrement();}}
private void executeTaskMain() {mStartTime = System.currentTimeMillis();for (Task task : mMainThreadTasks) {long time = System.currentTimeMillis();new DispatchRunnable(task,this).run();}}
首先是通过 getInstance()构造了一个实例对象,然后通过 addTask() 添加我们的 Task, 如果它不为空的话
根据上面的角标,逐一介绍
调用 collectDepends(),遍历该 task 所依赖的全部 task,并且以它所依赖的 task 为 Key, 本身为 Value 中集合元素的一员添加进去,然后判断,该 task 中的依赖是否已经加载过了,如果加载过了,调用该 task 的 satisfy()方法减该 task 的一把锁。
然后将这个 task 和它的 class 文件添加到 2 个集合中,方便后面使用。
如果该 Task 需要主线程等其完成再执行的话,则添加到等待队列中,等待队列计数器+1
打印该 task 所依赖的信息
拓扑排序,经典的算法,用于描述依赖关系的排序,在上一章节有过介绍也给出过源码,这里就不再赘述
这里实际上就是构建一把锁,这个锁注意并不在 Task 里面,Task 里面的锁,注意是为了先执行依赖的 Task,执行完毕,再执行自己,而这里的锁是在启动器上,其作用是让主线程等待,优先执行那些必须要先执行完毕才能让主线程继续执行完毕,再跳转页面的 task
评论