android 线程(AsyncTask,Threadhandler,intentService)详解

来源:互联网 发布:阜宁新闻网络发言人 编辑:程序博客网 时间:2024/04/26 01:39
有关线程的讲解,不断的深入,前面是整体的概括性东西,后面针对详细的讲解。
1.1 线程分为主线程和子线程:
主线程处理和界面相关的事情,
子线程处理耗时操作
除了Thread 之外还有AsyncTask(底层是线程池) 和 IntentService handlerThread

不同形式的线程,具有不同的特性和使用场景,
asyncTask: 封装了线程池和Handler,主要方便开发者在子线程中更新UI;
HanlderThread: 具有消息循环的线程,在它的内部可以使用Handler,
IntentService: 内部采用HandlerThread来执行任务,执行完毕后intentService会自动退出

线程池:在一个进程中频繁地创建和销毁线程,就会采用线程池;

2.1主线程和子线程
主线程是指进程所拥有的线程,java默认情况下一个进程只有一个线程,这个线程就是主线程
主线程主要是与用户交互的,所以主线程在任何时候都必须有较高的响应.速度,如果我们在主线程中做耗时操作,就会发生卡顿线程感觉,这个时候我们就需要子线程了,用子线程做耗时操作,(I/O操作,网络请求,文件读写),
如果我们在主线程中做更新UI的操作就会造成ANR无响应现象;

3.1 android中线程形态
除了Thread之外,我们还有AsyncTask,HandlerThread ,IntentService,这三者的底层也是线程;
3.2 AsyncTask(抽象类)
是一种轻量级的异步任务类,在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程
中更新UI,
AsyncTask封装了Thread和Handler,但是AsyncTask并不适合特别耗时的后台任务,对于特别耗时
AsyncTask做耗时操作不足之处:
1)存在大量消耗系统资源和导致应用FC风险(软件崩溃,出现问题)
2)AsyncTask一旦执行doInBackground,就算调用取消,也会将代码执行完毕才会停止;
3)线程池不经维护,当大量异步发生时,导致线程池满了会出异常。


任务来说,建议使用线程池;
AsyncTask是一个抽象泛型类,提供了Params,Progress和Result这三个泛型参数;
params:表示参数的类型,
Progress: 表示后台任务的执行的进度类型
Result: 后台任务返回结果的类型

AsyncTask这个类的声明如下:

AsyncTask提供了四个核心方法;、
1)onPreExecture();在主线程中执行了,在异步任务执行之前,此方法被调用,做一些准备工作;
2)doInBackground(Params):在线程池中执行,此方法用于执行异步任务,params参数表示
异步任务的输入参数,在此方法中可以通过publishProgress方法更新任务进度条,publicshProgress方法会调用onProgressUpdate方法,此方法将结果返回onPostExecture方法
3)onProgressUpdate(Progress)在主线程中执行,当后台任务执行进度发生改变时此方法会被调用;
4) onPostExecute(Result)在主线程中执行,异步任务执行之后,此方法会被调用,
result是后台任务返回值,

上面几个方法执行顺序:
onPreExecture先执行,接着doInBackground,最后才是onPostExecute,
除了上边这四个方法外,AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,
当异步任务被取消时,onCancelled()方法会被调用,onPostExecute()不会被调用;

AsyncTask使用过程中有一些条件限制。
1)AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程;
2)AsyncTask的对象必须在主线程中创建;
3)execute方法必须在UI线程调用
4)不要在程序中直接调用 onPreExecute(),onPostExecute,doInBackground和onProGressUpdate方法;
5)一个AsyncTask对象只能执行一次,即只能调用一次execute方法,

AsyncTask源码分析
分析AsyncTask的工作原理,我们从execute开始分析,execute这个方法会调用executeOnExecutor方法;

sDefaultExecutor实际上是一个串行线程池,一个进程中所有的AsyncTask都在这个串行的线程池中
排队执行,
分析线程池的执行过程:

分析AsyncTask排队执行过程,系统会把AsyncTask的Params参数封装为FutureTask对象,FutureTask是一个并发类,并交给SerialExecutor的execute方法去处理,execute方法会把FutrueTask对象插入任务队列mTask中,如果这个时候没有正在活动的AsyncTaskk任务,就调用
SerialExecutor的scheduleNext方法执行下一个AsyncTask任务。当一个AsyncTask任务执行完毕后,会继续执行其他任务,直到任务都被执行为止,
AsyncTask有两个线程池,serialExecutor和THREAD_POOL_EXECUTOR和一个Handler,
其中线程池SerialExecutor是用于任务的排队,THREAD_POOL_EXECUTOR用于真正的执行任务;
InternalHandler用于将执行环境从线程池切换到主线程,


为了能够将执行环境切换到主线程,这就要要求sHandler这个对象必须在主线程中创建,
sHandler收到MESSAGE_POST_RESULT这个消息后调用asyncTask的finish()方法;

如果AsyncTask被取消执行后,就调用onCancelled()方法,否则会调用onPostExecute方法,
doInBackground的返回结果会传递给onPostExecute方法,
到这里整个工作过程就结束了;

3.3 HandlerThread
HandlerThread继承Thread,它是一种可以使用Handler的Thread,
实现:在run方法中通过Looper.LoopPrepare(),来创建一个消息列队,并通过Looper.Loop()来开启消息的循环,也就是说在实际使用中可以在HandlerThread中创建Handler,
run方法如下:

HandlerThread的实现与Thread有显著的不同,Thread的run方法中执行一些耗时的操作,而HandlerThread在内部创建消息列队,外界通过handler的消息通知HandlerThread来执行一个任务,
HandlerThrread 是一个无限循环,当我们不在使用HandlerThread的时候,我们通过quit或者quitSafely方法终止线程的执行,

3.4 IntentService
IntentService是一个特殊的service,继承service,是一个抽象类,,intentService可用来执行后台的耗时操作,任务执行后会自动停止,由于intentService是服务的缘故,优先级要比普通的线程要高。
所以IntentService比较适合一些高优先级的后台任务,
IntenrtService封装了HandlerThread和Handler,可以通过onCreate()方法中看出:

当IntentService被第一次启动时,onCreate方法会被调用,并创建一个HandlerThread,用它的
Looper来构造一个handler对象mServiceHandler,通过这个对象发送的消息最终会在HandlerThread中执行,可以看出IntentService可以执行后台任务,每次启动IntentService,它的onStartCommand()方法就会调用一次,onStartCommand()方法会调用onStart();

onStart()方法用过mServiceHandler发送一个消息,这个消息会在HanlderThread中被处理。
mServiceHandler收到消息后,会将Intent对象传递给onHandlerIntent方法去处理。
(onHandlerIntent主要对不同的后台任务做处理)
当onHnadlerIntent方法执行结束,IntentService会通过stopSelf(int startId)来尝试停止服务;
对于stopSelf(int startId)与stopSelf()区别:
stopSelf()会立刻停止服务,不管消息处理完毕没有
stopSelf(int startId):等待所有消息处理完毕后在终止服务;
通过判断最近启动服务的次数是否和startId相等,如果相等就停止服务,
可以通过AMS的stopServiceToken方法找到依据。

阅读全文
1 0