android经常使用异步框架分为handler、AsyncTask、handlerThread、IntentService。java
android消息机制的上层接口,经过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue。android
1. 可让对应的Message和Runnable在将来的某个时间点进行相应的处理。
1. 让本身想要处理的耗时操做放在子线程,让更新ui放在主线程。
复制代码
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } 复制代码
在handler的构造方法中建立looper,而后根据looper的成员变量建立MessageQueue这样handler就和MessageQueue关联在了一块儿,而MessageQueue是经过Looper来管理的,从而三者关联在了一块儿; 咱们点进去看下Looper.myLooper方法,发现是从sThreadLocal获取的,ThreadLocal是每一个线程都独有的一份数据,因此每一个handler获取的都对应本身线程的Looper。bash
public static @Nullable Looper myLooper() { return sThreadLocal.get(); } 复制代码
接着往下看发现sThreadLocal实在prepare()中赋值的,这样保证了每一个线程的惟一性。markdown
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } 复制代码
public static void loop() { ...省略部分不重要代码 for (;;) { Message msg = queue.next(); // might block try { msg.target.dispatchMessage(msg); } msg.recycleUnchecked(); } } 复制代码
其实就是建立了一个for死循环,逐个取出msg,经过Handler(msg.target)dispatchMessage(msg)并发
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 复制代码
dispatchMessage,其实就是中转器,根据不一样的条件不一样的处理方式。框架
非静态内部类持有外部类的引用,handler里面有可能里面有耗时或者延时操做,当activity销毁后因为handler持有activity,致使activity没法释放,形成了内存泄露。 解决方案:handler设置为静态内部类,在activity的onDestroy中调用handler.removeCallBack()。注意若是在静态内部类中,若是要使用activity,必定用弱引用,而不是直接使用activity。异步
AsyncTask能够用来处理一些后台较耗时的任务,查看源码发现其内部就是一个Handler和线程池的封装,能够帮助咱们处理耗时任务的同时去更新UI。async
public abstract class AsyncTask<Params, Progress, Result> {
......
}
Params 启动任务执行的输入参数,好比下载URL
Progress 后台任务执行的百分比,好比下载进度
Result 后台执行任务最终返回的结果,好比下载结果
复制代码
onPreExecute():(运行在UI线程中) (非必须方法) 在任务执行前调用,一般用来作一些准备操做,好比下载文件前,在显示一个进度条等。 doInBackground(Params... params):(运行在子线程中)(必须实现) 能够在此方法中处理比较耗时的操做,好比下载文件等等。 onProgressUpdate(Progress... values) (运行在UI线程中) (非必须方法) 此函数异步任务执行时,回调给UI主线程的进度,好比上传或者下载进度。 onPostExecute(Result result)(运行在UI线程中) (非必须方法) 此函数表明任务执行结束了,回调给UI主线程的结果。好比下载结果。 onCancelled(Result result)onCancelled()任务关闭的函数 复制代码
cancel (boolean mayInterruptIfRunning)取消执行任务 execute (Params... params)用指定的参数来执行此任务 executeOnExecutor(Executor exec,Params... params)在指定的Executor中执行任务。 getStatus ()得到任务的当)前状态 PENDING(等待执行)、RUNNING(正在运行)、FINISHED(运行完成) isCancelled ()在任务正常结束以前能成功取消任务则返回true,不然返回false 复制代码
内存泄露 非静态内部类持有外部类的引用;若是Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,致使Activity没法被回收,引发内存泄露。 解决方案:把AsyncTask设置为静态内部类,里面持有activity的弱引用。并在onDestroy中cancel()任务。ide
AsyncTask不与任何组件绑定生命周期 解决方案:在Activity/Fragment的onDestory()调用 cancel(true);函数
串行或者并行的执行异步任务 当想要串行执行时,直接执行execute()方法,若是须要并行执行,则要执行executeOnExecutor(Executor)。建议串行,保证线程池的稳定,AsyncTask通常作不了高并发,太耗时的操做。
结果丢失 屏幕旋转或Activity在后台被系统杀掉等状况会致使Activity的从新建立,以前运行的AsyncTask会持有一个以前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将再也不生效。
开启子线程进行耗时操做,屡次建立和销毁线程是很消耗系统资源的,google为咱们封装了handlerThread。它是有handler +thread +looper构成的。它是经过获取handlerThread的 looper对象传递给handler,而后在handleMessage执行异步任务。 优势是不会阻塞UI线程,缺点是串行执行,处理效率较低。
mHandlerThread = new HandlerThread("mHandlerThread");//这里的mHandlerThread其实就是线程的名字 mHandlerThread.start(); 复制代码
初始化Handler进行,传入mHandlerThread中的Looper,这样就保证了Handler运行在子线程,loop轮训,不一样的交给handleMessage处理消息。
workHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
...//消息处理
} }
};
复制代码
3.使用工做线程Handler向工做线程的消息队列发送消息
Message msg = Message.obtain(); msg.what = 2; //消息的标识 msg.obj = "B"; // 消息的存放 // b. 经过Handler发送消息到其绑定的消息队列 workHandler.sendMessage(msg); 复制代码
4.结束线程,即中止线程的消息循环 mHandlerThread.quit();
//1.Thread的子类 public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; private @Nullable Handler mHandler; //还记得上面的HandlerThread使用的初始化吗? public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } public HandlerThread(String name, int priority) { super(name); mPriority = priority; } //thread在开启start后会执行run方法,在这里会准备Looper并开启轮训。 @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } //还记得上面的Handler的建立吗? public Looper getLooper() { if (!isAlive()) { return null; } synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } //能够发送消息的异步Handler @NonNull public Handler getThreadHandler() { if (mHandler == null) { mHandler = new Handler(getLooper()); } return mHandler; } public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } public int getThreadId() { return mTid; } } 复制代码
注意点1:这里用了java线程知识,wait();和notifyAll(),为何这么用呢 首先,Handler的建立通常是在主线程完成的,建立的时候获取HandlerThread.getLooper(),而Looper的建立是在子线程中建立的,这里就有线程同步问题了,好比咱们调用getLooper()的时候HandlerThread中run()方法还没执行完,mLooper变量还未赋值,此时就执行了wait()等待逻辑,一直等到run()方法中mLooper被赋值,以后当即执行notifyAll(),而后getLooper()就能够正确返回mLooper了。 注意点2:quitSafely()和quit()有什么区别?
区别在于该方法移除消息、退出循环时是否在乎当前队列是否正在处理消息,不管是否正在执行此时quit()都会当即退出该循环。 如果正在处理quitSafely,则等待该消息处理处理完毕再退出该循环。
一个封装了HandlerThread和Handler的特殊Service,能够屡次启动,每一个耗时操做都会以工做队列的方式串行在IntentService的onHandleIntent回调方法中执行。任务执行完后会自动中止。
1.自定义LocalIntentService继承自IntentService
public class MyIntentService extends IntentService{
public LocalIntentService(String name) {
super(name);
}
}
复制代码
2.实现onHandleIntent(), 是耗时操做。
@Override protected void onHandleIntent(@Nullable Intent intent) { String action = intent.getStringExtra("task_action"); //dosomething } 复制代码
//IntentService第一次启动调用 public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } 复制代码
2.屡次启动会走startService()->onStartCommand()->onStart()经过HandlerThread的handler去发送消息。
@Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } 复制代码
3.IntentService的SerivceHandler
HandlerThread顺序取出任务执行,会调用ServiceHandler的 handleMessage()->onHandleIntent()。任务执行完毕后stopSelf(startId)中止Service。任务结束后,在onDestory()中会退出HandlerThread中Looper的循环。
//ServiceHandler接收并处理onStart()方法中发送的Msg private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); //会判断启动服务次数是否与startId相等 } } public void onDestroy() { mServiceLooper.quit(); } 复制代码