在Android中,一个应用程序就是一个独立的线程(应用运行在一个独立的环境中,可以避免其他进程的干扰)。一般来说,当我们启动一个应用程序的时候,系统会创建一个进程(从Zygote中fork出来的,这个进程会有独立的ID),并为这个进程创建一个主线程(UI线程),应用程序的组件默认运行在它的进程中,但我们可以通过制定应用的组件(四大组件)的运行进程:android:process来让组件运行在不同的进程中。 让组件运行在不同的进程中,有好处也会有坏处:
好处是:因为每个应用程序(进程)都会有一个内存预算,所有运行在这个进程中的程序使用的总内存不能超过这个值,让组件运行在不同的进程中,可以让主进程可以拥有更多的空间资源坏处是:每个进程都会有自己的虚拟机实例,因此让在进程间共享一些数据变得困难(当然,我们可以采用多线程间的通信来实现数据的共享)在java中,线程有几种状态:创建,就绪,运行,阻塞,死亡。当当应用程序有组件运行时,UI线程就处于运行状态。默认情况下,所有组件的操作都在UI线程完成的,包括相应用户的操作(触摸, 点击等),组件的生命周期方法调用,UI的更新等。因此如果UI线程阻塞(在线程里做一些耗时操作),就不能响应各种操作,如果阻塞时间达到5秒,就会出现ANR(Application not respoding)。 因为Android的UI线程是非线程安全的,应用更新UI,是调用invalidate()方法来实现界面的重绘,而invalidate()方法是非线程安全的,也就是说当我们在非UI线程更新UI时,可能会有其他线程或UI线程也在更新UI,这就会导致界面更新的不同步。因此我们不能在非UI线程做更新U的操作。需要保证:
不能阻塞UI线程,即不能再UI线程执行耗时操作,如网络连接,文件的IO等只能在UI线程更新UI当我们启动一个APP时,Android系统会启动一个Linux Process,该Process包含一个Thread,就是UIThread。因为UI Thread是非线程安全的,所以我们需要使用其他线程去完成一些耗时操作,因此就需要用到多线程。
Android 提供了四种常用的操作多线程的方式: Handler+Thread,AsyncTask,ThreadhreadPoolExecutor,IntentService
Handler是Android引入的一种让开发者参与与处理线程中消息循环的机制。我们在使用Handler的时候与Message打交道最多,Message是Handle机制向开发人员暴露出来的相关类,可以通过Message相关类完成大部分操作Handle的功能。Handler的内部实现主要涉及如下几个类:Thread、MessageQueue和Looper:
Thread是最基础的,Looper和MessageQueue都是构建在Thread之上,Handler有构建在Looper和MessageQueue之上,我们通过Handler间接的与下面几个相对底层的类打交道。
MessageQueue源码链接 最基础最底层的是Thread,每一个线程内部都维护了一个消息队列—MessageQueue。消息队列MessageQueue,就是存放消息的队列。 假设我们在UI界面点击了某个按钮,而此时程序收到了某个广播事件,那我们如何处理这两个事件呢?因为一个线程在某一个时刻只能处理一件事情,不能同时处理多件事情,所以我们只能挨个处理。为此Android把UI界面上单机按钮的事件封装成一个Message,将其放入了MessageQueue,即将点击按钮事件的Message入栈到消息队列中,然后再将广播事件封装成Message,也入栈到消息队列中。可以说Message对象表示线程需要出的一件事情,消息队列就是一堆需要处理的Message池。线程Thread会依次取出消息队列中的消息,依次对其进行处理。 MessageQueue中有两个重要的方法,一个是enqueueMessage方法,一个是next方法: enqueueMessage() :将一个message放入到消息队列MessageQueue中 next():从消息队列MessageQueue中阻塞式地取出一个Message 在Android中,消息队列负责管理着顶级程序对象(Activity,BroatcastReceive等)以及由其创建的所有窗口。
Looper源码链接 消息队列只是存储Message的地方,真正让消息循环起来的是Looper。 Looper是用来让线程中的消息循环起来的。默认情况下当我们创建一个新的线程时候,这个线程里是没有消息队列MessageQueue的。为了能够让线程绑定一个消息队列,我们需要借助与Looper: 首先我们要调用Looper的prepare方法,然后调用Looper的Loop方法
class LooperThread extends Thread{ public Handler mHandler; public void run(){ Looper.prepare(); mHandler = new Handler(){ public void handlerMessage(Message msg){ // } }; Looper.loop(); } }需要注意的是Looper.prepare() 和 Looper.loop() 都是在新线程的run方法内调用,这两个方法都是静态方法。我们通过查看Looper的源码可以发现,Looper的构造函数是private的,也就是在该类的外部不能用new Looper() 的形式得到一个Looper对象。根据我们上面的描述,我们知道线程Thread 和 Looper 是一对一绑定的,也就是一个线程最多只能有一个Looper对象,这就解释了Looper的构造函数为什么是private得了,我们只能通过工厂方法 Looper.myLooper() 这个静态方法获取当前线程所绑定的Looper。
Looper通过如下代码保存了对当前线程的引用:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();所以在Looper对象中通过 sThreadLocal 就可以 找到其绑定的线程。
1、Looper.prepare() :该方法是让Looper做好准备,只有Looper准备好了之后才能调用Looper.loop()方法,Looper.prepare()的代码如下:
private static void prepare(boolean quitAllowed){ if(sThreadLocal.get() != null){ throw new RuntimeExecuption("only one looper may be created per thread") } sThreadLocal.set(new Looper(quitAllowed); }上面的代码,sThreadLocal.get() 拿到线程sThreadLocal所绑定的Looper对象,由于初始化情况下sThreadLocal并没有绑定Looper,所以第一次调用prepare方法时,sThreadLocal.get() 返回null,不会抛出异常。然后执行sThreadLocal.set(new Looper(quitAllowed) ,先通过私有构造函数创建一个Looper对象的实例,然后通过set方法将该Looper绑定到sThreadLocal中。 这样就通过 prepare方法完成了 线程 sThreadLocal 与 Looper的双向绑定:
在Looper内通过sThreadLocal可以获取Looper所绑定的线程线程sThreadLoca通过sThreadLocal.get() 方法可以获取该线程所绑定的Looper对象Looper的私有构造方法,代码如下:
private Looper(boolean quitAllowed){ mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }我们可以看到构造方法中实例化了一个消息队列MessageQueue,并将其赋值给其成员字段mQueue,这样Looper也就与MessageQueue通过成员字段进行了关联。
在执行完Looper.prepare(双向绑定,线程与Looper的绑定)之后,我们就可以在外部通过Looper.myLooper() 方法获取当前线程绑定的Looper对象。 myLooper方法如下:
public static Looper myLooper(){ return mThreadLocal.get(); }需要注意的是,在一个线程中,只能调用一次Looper.prepare(),因为在第一次调用了Looper.prepare之后,当前线程就已经绑定了Looper,在该线程内第二次调用Looper.prepare方法的时候,sThreadLocal.get()会返回第一次调用prepare的时候被绑定的Looper,不是null,这样就会抛出异常 throw new RuntimeExceition (“Only one looper may be created per thread”) ,告诉开发者一个线程只能绑定一个Looper对象。
在调用Looper.prepare方法之后,就可以调用Looper.loop方法让消息队列循环起来了。 注意:Looper.loop()应该在该Looper所绑定的线程中执行
Looper.loop()的代码如下:
public static void loop(){ final Looper me = myLooper(); if( me == null){ throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread"); } //注意下面这行 final MessageQueue queue = me.mQueu(); //Make sure the identity of this thread is that of the local process, //and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); //注意下面这行 for(;;){ //注意下面这行 Message mas = queue.next(); //might block if(msg = null){ //No message indicates that the message queue is quitting. return; } //this must be in a loca variable, in case a UI event sets the logger Printer logging = me.mLogging; if(logging != null){ logging.pringln(">>>> Dispatching to "+msg.target+" "+msg.callback + “: ”+mag.what); } //注意下面这行 msg.target.dispatchMessage(mag); if(logging != null){ logging.pringln("<<<< Finished to " + msg.target +" " +mag.callback); } //Make sure that during the course of dispatching the //identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if(ident != newIdent){ Log.wtf(TAG,"Thread identity changed from 0x" + Long.toHexString(ident)+"to 0x" + Long.toHexString(newIdent)+ "while dispatching to " + msg.target.getClass().getName()+" " + mag.callback +" what=" + mag.what); } msg.recycleUnchecked(); } }`上面有几行代码是关键代码: 1、final MessageQueue queue = me.mQuue; 变量me 是通过静态方法myLooper()获取的当前线程所绑定的Looper(), me.mQueue是当前线程所关联的消息队列。 2、for(;?; 我们发现for循环没有设置循环终止的条件,所以这个for循环是个死循环。 3、Message msg = queue.next() 我们通过消息队列MessageQueue.next 方法从消息队列中取出一条消息,如果此时消息队列中有Message,那么next会立即返回该Message,如果此时消息队列中没有Message,那么next方法就会阻塞式地等待获取Message。 4、msg.target.diapatchMessage(msg); msg的rarget属性时Handler,该代码的意思是让Message所关联的Handler通过dispatchMessage方法让Handler处理该Message,关于Handler的dispatchMessage方法将会在下面介绍
Handler源码链接 Handler 是暴露给开发者最顶层的一个类,其构建在Thread、Looper与MessageQueue之上,Handler具有多个构造函数,签名分别如下:
publicHandler()publicHandler(Callback callback)publicHandler(Looper looper)publicHandler(Looper looper, Callback callback) 第一个和第二个构造函数都没有传递Looper,这两个构造函数都将通过调用Looper.myLooper()获取当前线程绑定的Looper对象,然后将该Looper对象保存到名为mLooper的成员字段中。 第二个和第四个构造函数还传递了Callback对象,Callback是Handler中的内部接口,需要实现其内部的handleMessage方法,Callback代码如下: public interface Callback(){ public boolean handleMessage(Message msg) }Handler.Callback 是用来处理Message的一种手段,如果没有传递此参数,那么久应该重写Handler的handleMessage方法,也就是说为了使得Handler能够处理Message,我们有两种方法:
向handler构造函数传入一个Handler.Callback对象,并实现Handler.Callback的handleMessage方法无需向Handler的构造函数传入Handler.Callback对象,但是需要重写Handler本身的handleMessage方法这一点与java中使用多线程有异曲同工之妙,java中,如果要使用多线程,有两种方法:
向Thread的构造函数传入一个Runnable对象,并实现Runnable的run方法无需向Thread的构造函数传入Runnable对象,但是需要重写Thread本身的run方法sendMessage系列方法 我们通过sendMessageXXX系列可以向消息队列中添加消息,我们通过源码可以看到这些方法的调用顺序: sendMessage 调用了sendMessageDelayed, sendMessageDelayed 又调用了 sendMessageAtTime。
Handler中还有一系列的sendEmptyMessageXXX方法,而这些方法在其内部有分别调用了其对应的sendMessageXXX方法。如图:
由此可见,所有的sendMessageXXX方法和sendEmptyMessageXXX方法最终都调用了sendMessageAtTime方法。
post系列方法 我们来看看postXXX方法,会发现postXXX方法在其内部又调用了对应的sendMessgeXXX方法,我们可以查看下sendMessage的源码:
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); }可以看到内部调用了getPostMessage 方法,该方法传入了Runnable对象,得到了一个Message对象,getPostMessage的源码如下:
private static Message getPostMessage(Runnable r){ Message m = Message.obtain(); m.callback = r; return m; }上述代码我们可以看到,在getPostMessage中,我们创建了一个Message对象,并将传入的Runnable对象赋值给Message的callback成员字段,然后返回该Message,然后在post方法中将携带有Runnable信息的Message传入到sendMessageDelayed方法中。由此我们可以看到所有的postXXX方法内部都需要借助sendMessageXXX方法来实现,所以postXXX与sendMessageXXX并不是对立关系,而是postXXX依赖sendMessageXXX,所以postXXX方法可以通过sendMessageXXX方法向消息队列中传入消息,只不过通过postXXX方法想消息队列中传入的消息都携带有Runnable对象(Message.callback) 我们可以通过关系图看清楚postXXX与sendMessageXXX方法之间的调用关系:
通过分析sendEmptyMessageXXX,postXXX方法与sendMessageXXX方法之间的关系,我们可以看到Handler中所有可以直接或间接向消息队列发送Message的方法最终都调用了sendMessageAtTime方法,该方法的源码如下:
public boolean sendMessageAtTime(Message msg, long uptimeMillis){ MessageQueue queue = mQueue; if(queue == null){ RuntimeException e = new RuntimeException( this +" sendMessageAtTime() called with no mQueue"); Log.w("Looper",e.getMessage(),e); return false; } //注意下面这行代码 return enqueueMessage(queue, msg, uptimeMillis); }该方法内部调用了enqueueMessage方法,该方法的源码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis){ //注意下面这行 msg.target = this; if(mAsynchronous){ msg.setAsynchronous(true); } //注意下面这行代码 return queue.enqueueMessage(msg, uptimeMillis); }该方法中有两件事需要注意: 1,msg.target = this 该代码将Message的target绑定为当前的Handler 2.queue.enqueueMessage 变量queue表示的是Handler所绑定的消息队列MessageQueue,通过queue.enqueueMessage(msg, uptimeMills),我们将Message放入到消息队列中
所以我们通过下图看一下完整的方法调用顺序:
我们在分析Looper.loop() 源码时知道,Looper一直不断从消息队列中通过MessageQueue的next方法获取Message,然后通过代码msg.target.diapathchMessage(msg) ,让该msg所绑定的Handler(Message.target)执行diapatchMessage方法以实现对Message的处理。 Handler的dispatchMessage的源码如下:
public void dispatchMessage(Message msg){ //注意下面这行 if(msg.callback != null){ handleCallback(msg); }else { //注意下面这行 if(mCallback != null){ if(mCallback.handleMessage(msg)){ return; } } //注意下面这行 handleMessage(msg); } }我们来分析这段代码:
首先判断msg.callback是否存在,msg.callback是Runnable类型,如果msg.callback存在,那么说明该Message是通过执行Handler的postXXX系列方法将Message放入消息队列中的,这种情况下会执行handleCallback(msg), handleCallback源码如下:
private static void handleCallback(Message message){ message.callback.run(); }这里我们可以清楚的看到,我们执行了message.callback.run 方法,也就是执行了Runnable对象的run方法。
如果我们不是通过postXXX系列方法让Message的话,那么msg.callback就是null,代码往下执行,接着判断Handler的成员字段mCallback是否存在。mCallback是Handler.Callback类型,在构造函数中,我们可以传递Handler.Callback类型的对象,该对象需要实现handlerMessage方法,如果我们在构造函数中传递了该Callback对象,那么我们会让Callback的handleMessage方法来处理Message。如果我们在构造函数中没有传入Callback类型对象,那么mCallback为null,那么我们会调用Handler自身的handleMessage方法,该方法默认是个空方法,我们需要自己重写实现该方法综上,我们可以看到Handler提供了三个途径来处理Message,而且处理有前后优先之分:首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法,最后才是让Handler自身的handleMessage方法处理Message
下面用一个大神的图 @孙群 来更形象的理解Handler机制:
转自:https://blog.csdn.net/iispring/article/details/47180325
AsyncTask 是一个抽象类,它是由Android封装的一个轻量级异步类(轻量级体现在使用方法,代码简洁),它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。
AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和 Handler(InternalHandler)。
其中SerialExecutor 线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR 线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。
AsyncTask的类声明如下:
public abstract class AsyncTask<Params, Progress, Result>AsyncTask 是一个抽象泛型类。 其中,三个泛型类型参数的含义如下: Params :开始异步任务执行时传入的参数类型; Progress:异步任务执行过程中,返回下载进度值的类型; Result:异步任务执行完成后,返回的结果类型; 如果AsyncTask确定不需要传递具体的参数,那么这三个泛型参数可以用Void代替。
上面几个方法的调用顺序: onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()
如果不更新执行顺序为: onPreExecute() -->doInBackground() --> onPostExecute()
除了上面几个方法,AsyncTask还提供了onCancelled()方法,它同样在主线程中运行,当异步任务取消时,onCancelled()会被调用,这个时候onPostExecute()则不会被调用,但是要注意的是:AsyncTask中的cancell()方法并不是真正去取消任务,只是设置这个任务为取消状态,我们需要在doInBackground()判断终止任务,就好比想要终止一个线程,调用interrupt()方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。
这里我们模拟了一个下载任务,在doInBackground()方法中执行具体的下载逻辑,在onProgressUpdate方法中显示当前的下载进度,在onPostExecute方法中来提示任务的执行结果。如果想要启动这个个任务,只需要简单的调用下列代码即可:
new DownloadTask().execute();先从初始化一个AsyncTask时,调用的构造函数开始分析:
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); //noinspection unchecked 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); } } }; }这段代码比较长,但实际上没有任何具体的逻辑会得到执行,只是初始化了两个变量,mWorker 和 mFuture,并在初始化mFuture的时候将mWorker作为参数传入。mWorker是一个Cllable对象,mFuture是一个FutureTask对象,这两个变量会暂时保存在内存中,稍后才会用到它们。FutureTask实现了Runnable接口,关于这部分内容,可以看这篇文章
mWorker中的call()方法执行了耗时操作,即 result = doInBackground(mParams);然后把执行结果通过postResult(result),传递给内部的Handler跳转到主线程中。这里实例化了两个变量,并没有开启执行任务。
那么mFuture对象是怎么加载到线程池中,进行执行的呢?
接着如果想要启动某一个任务,就需要调用该任务的execute()的方法,因此现在我们来看一看 execute()方法的源码:
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }调用了executeOnExecutor方法,具体逻辑如下:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { 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)"); } } mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }可以看出,先执行了onPreExecute()方法,然后具体执行耗时操作任务的是exec.execte(mFuture) ,把构造函数中实例化的mFuture传递进去了。
exec具体是什么
从上面可以看出具体是sDefaultExecutor,再追溯看到是SerialExecutor类,源码如下 :
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }我们可以看到execute方法。SerialExecutor是个静态内部类,是所有实例化的AsyncTask对象共有的,SerialExecutor内部维持了一个队列,通过锁使得该队列保证AsyncTask中的任务是串行执行的,即多个任务需要一个个加到该队列中,然后执行完队列头部的再执行下一个,以此类推。
在这个方法中,有两个主要步骤:
对队列中加入一个新的任务,即之前实例化后的mFuture对象调用*scheduleNext()方法**,调用THREAD_POOL_EXECUTOR执行队列头部的任务由此可见,SerialExecutor类仅仅为了保持任务执行是串行的,实际执行交给了THREAD_POOL_EXECUTOR。
THREAD_POOL_EXECUTOR 又是什么?
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true); THREAD_POOL_EXECUTOR = threadPoolExecutor;实际上是一个线程池,开启了一定数量的核心线程和工作线程。然后调用线程池的execute() 方法,执行具体的耗时任务,即开头构造函数中中mWorker中call()方法de的内容。先执行完 doInBackground() 方法,又执行postResult()方法,下面具体看这个方法:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }该方法向Handler对象发送了一个消息,下面来看AsyncTask中实例化的Handler对象的源码:
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } } }在InternalHandler中,如果收到的消息是MESSAGE_POST_RESULT, 即执行完了doInBackground() 方法并传递结果,那么就调用finish()方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }如果任务取消了,回调onCancelled() 方法,否则回调onPostExecute() 方法。
如果收到的消息是MESSAGE_POST_PROGRESS, 回调onProgressUpdate() 方法,更新进度。
InternalHandler是一个静态类,为了能够将执行环境切换到主线程,因此这个类必须在主线程中加载,所以变相要求AsyncTask的类必须在主线程中加载
线程池实现;
IntentService 具有Service 一样的生命周期,也提供了后台线程的异步处理机制。
public class MyIntentService extends IntentService { public MyIntentService() { super(""); } @Override protected void onHandleIntent(Intent intent) { try { Thread.sleep(3*1000); } catch (InterruptedException e) { e.printStackTrace(); } Intent intentresult = new Intent(IntentServiceActivity.RESULT); sendBroadcast(intentresult); } public void onDestroy() { super.onDestroy(); } }这里我们通过广播,将结果返回到源Activity进行界面更新的,这样的处理方式感觉很重,如非设计流程需要使用,不建议经常使用。 在看一下如何启动:
Intent intent=new Intent(IntentServiceActivity.this,MyIntentService.class); startService(intent);