一、AsynTask
1、构造NuAsyncTask实例
该类是一个泛型类,取消了Process参数(因为更多情况下使用不到,保证接口的简洁性),只保留了Params,Result类型参数;
另外,构造函数必须要求传入一个workName,以便来跟踪任务的执行时间。因为AsyncTask任务可以调用取消接口,所以该类为了
保证功能的一致性,定义了一个NuFutureRunnable类,以来可以取消提交的任务。
2、抽象接口定义
抽象接口的定义,同AsyncTask的 doInBackground,onPostExecute;因为不需要关注Process,所以取消了onProgressUpdate接口的定义;用户在使用的时候,只要按照
创建一个NuAsyncTask对象,实现抽象函数接口,doInBackground保证在子线程执行任务,onPostExecute保证在UI线程回调结果。
3、任务的提交与执行
提交任务,可以调用execute接口或executeOnExecute接口,如果是execute接口,框架层有个默认的线程池执行器;如果是executeOnExecute,外部可以根据自身需求来指定执行器,最终会调用到
NuExecutor的submit接口,提交一个“未来任务”,并且执行接口回调到UI线程,由上面代码可以看到,在线程池整理框架的基础上,重新包装调用了抽象接口doInBackground与onPostExecute,通过这样的包装,
可以满足不同用户的偏好需求,但是线程任务的执行,都是统一通过线程池整理框架进行分配管理。
4、任务的取消
取消可以调用cancel接口,该接口会原子操作保存当前取消的值,用户可以根据isCancelled来判断当前的任务取消状态;然后就会调用mFutureRunnable的cancel接口,
尝试的取消任务,否则直接返回false,无需要做任何取消动作;监听是否取消,用户可以通过复写接口onCancelled接口来处理取消后的任务。
5、总结
由此可见,NuAsyncTask的用法跟AsyncTask的用户完全类似,并且简化的使用方式,使得使用起来更简洁易用,通过最后巧妙的包装,内部的实现转接到了NuExecutor类,跟之前的线程池管理巧妙
的关联起来,从而实现的统一管理的目的。
二、HandlerThread
1、构造NuThreadHandler实例
如上图所示:传入一个ThreadInfo对象,该对象描述了一个线程的名字,优先级等信息;然后调用构造的核心方法createHandler,在该方法里面,内部根据threadinfo信息创建了一个HandlerThread对象,
接着实例化Hanlder来处理异步消息。
由此可见,NuThreadHandler内部实现的ThreadHandler,这样就避免了外部随意创建HandlerThread对象,导致线程不可控的现象。
2、对外暴露接口 send与post方式
可以通过send的方式发送一个Message对象,也可以通过post的方式发送一个Runnable对象,可以根据不同的需求来调用响应的接口方法,核心的实现代码都是在sendMessageInner,代码如下:
step1:Message.what采用的是一个全局唯一值WHAT_GLOBAL_TOKEN,目的是为了统一标识所有的send或post方式发送的消息,便于取消所有的任务
step2:区分srcObj是Message对象还是Runnable对象,如果是Message对象,m.obj来记录srcMsg的what值,其他信息保存到m.data(Bundle)对象中去,
如果未Runnable对象,直接保存到m.obj中去
step3:最后,调用内部异步Handler对象,发送当前的消息,该消息在doMessage中处理。
3、消息处理doMessage
首先,根据发送过来的Message对象中obj进行区分,根据上面步骤的分析,如果obj为Runnable对象,说明采用的post方式;如果对象时Message对象,说明采用的是send方式。
其次,如果是Runnable对象,直接执行NuRunnable.run方法,因为NuRunnable对于任务的执行时间有统计,所以,改出不在进行统计。
最后,如果是Message对象,需要通过MSG_OBJ获取到原始的srcMessage对象,然后交由 handleMessage(需要子类实现)接口进行处理,并统计了该Message处理的时长
4、任务取消cancel
取消任务,可以根据 what方式取消,也可以根据Runnable方式取消,也可以取消所有的消息,调用的接口是Handler.removeMessages接口,第一个参数都表示what,第二参数表示obj
5、删除消息removeMessages原理解读
三、ThreadPoolExecutor
1、再包装该类
如下图所示,通过继承的方式包装该类,以后项目中有使用ThreadPoolExecutor类的地方,都统一使用NuExecutor类
该类只暴露的2个构造函数,简化用户的使用,同时,外部实例化的时候,必须制定一个该线程池的名称,便于追本溯源。
2、execute接口包装
如下图所示,对于之前的接口标识了@Deprecated,原则:Deprecated的接口禁止调用
新增了 NuRunnable参数接口,外部应当调用该接口(NuRunnable是单个任务执行器,包含了任务时长统计等行为,本文不细阐述)
3、submit接口包装
如下图所示,同execute原则,原始的接口进行弃用
新增参数为NuRunnable,返回值为NuFutureRunnable的接口(NuFutureRunnable是对FutureTask的包装)
4、线程池线程创建
如下图所示,线程池中线程的命名规则:nuBrowser-thread-executorName-number
这样便于区分线程池(线程池线程只是执行Runnable,所以每个任务的执行时长在Runnable中进行统计,本文不再赘述NuRunnable类,知晓该类职责即可)
另外,每个线程统计了该线程的存活时长(如果需要,甚至可以统计该线程执行了的任务个数等信息,根据项目需要进行扩展)
5、线程中断监控
如下图所示,在NuExecutor中有两个方法,每当线程池开始执行任务时候,会回调beforeExecute和afterExecute方法,可以在此方法记录当前线程将要执行的任务
在线程被中断,即被调用到interrupt接口的时候,统计当前的任务信息,并进行输出,便于跟踪问题。
总结:在今后项目中,凡是用到线程池概念或者ThreadPoolExecutor类的地方,都必须统一使用NuExecutor类,这样便于项目中进行必要信息的统计采集。