基本概述:Handler就是解决线程与线程间的通信。
Handler是Android提供的用来更新UI的一套机制,也是一套消息处理机制,我们可以通过它发送消息,也可以通过它处理消息。
为什么要使用Handler:
Android在设计的时候,就封装了一套消息创建、传递、处理机制,如果不遵循这样的机制就没有办法更新UI信息,就会抛出异常。
为什么Android要设计只能通过Handler机制更新UI:
最根本的目的就是解决多线程并发问题。
如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,那么就会导致更新界面错乱;如果对更新UI的操作都进行加锁处理,又会造成性能下降。
基于对以上目的的考虑,Android给我们提供了一套更新UI的机制,我们只需遵循这样的机制,无需考虑多线程问题。
Handler的原理是什么:
Handler封装了消息的发送:内部会跟Looper关联
Looper(消息封装的载体):内部包含一个消息队列(MessageQueue),所有Handler发送的消息都会走向这个消息队列;
Looper.Looper方法是一个死循环,不断的从MessageQueue取消息,如果有消息就处理消息,没有消息就阻塞
MessageQueue(消息队列):可以添加消息,并处理消息
总结:Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己(handleMessage),MessageQueue就是一个存储消息的容器。
消息处理机制本质:一个线程开启循环模式持续监听并依次处理其他线程给它发的消息。
Handler引起的内存泄漏:
原因:Hndler非静态内部类持有外部类的匿名引用,导致外部类无法被回收;
具体描述:Handler非静态的内部类会持有当前Activity的引用,而Handler又被Message持有,Message被MessageQueue持有,而MessageQueue又被Looper持有,Looper被主线程持有,主线程是不会回收的,通过这条引用链就会导致Activity无法回收。在这之中如果Message在还没处理完成之前,他会一直处在消息队列中,至少等消息处理完才会销毁这个Message,销毁Message才会销毁Handler,进而回收Activity,因此在此期间就会导致内存泄漏。
解决办法:handler内部持有外部Activity的弱引用,并把handler改为静态内部类,然后在onDestroy方法中调用handler的removeCallBack()方法
非UI线程真的不能更新UI吗?
以下代码就能正常执行并且将tvText设置为new value。因为setText操作是在onCreate里面进行的,然后在onResume方法被执行后我们的ViewRootImpl才会被生成,所以并未执行相应的checkThread()操作。
public class MainActivity extends Activity {
private TextView tvText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvText = (TextView) findViewById(R.id.main_tv);
new Thread(new Runnable() {
@Override
public void run() {
tvText.setText("new value");
}
}).start();
}
}
Handler组成部分:1.Message 2.Handler 3.Message Queue 4.Looper 5.ThreadLocal
Looper
每一个线程只有一个Looper,每个线程在初始化Looper之后,然后Looper会维护好该线程的消息队列,用来存放Handler发送的Message,并处理消息队列出队的Message。它的特点是它跟它的线程是绑定的,处理消息也是在Looper所在的线程去处理,所以当我们在主线程创建Handler时,它就会跟主线程唯一的Looper绑定,从而我们使用Handler在子线程发消息时,最终也是在主线程处理,达到了异步的效果。
那么就会有人问,为什么我们使用Handler的时候从来都不需要创建Looper呢?这是因为在主线程中,ActivityThread默认会把Looper初始化好,prepare以后,当前线程就会变成一个Looper线程。Looper的创建是通过ThreadLocal,在每个线程都创建独立的Looper。
MessageQueue
MessageQueue是一个消息队列,用来存放Handler发送的消息。每个线程最多只有一个MessageQueue。MessageQueue通常都是由Looper来管理,而主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper。
Message
消息对象,就是MessageQueue里面存放的对象,一个MessageQueue可以包括多个Message。当我们需要发送一个Message时,我们一般不建议使用new Message()的形式来创建,更推荐使用Message.obtain()来获取Message实例,因为在Message类里面定义了一个消息池,当消息池里存在未使用的消息时,便返回,如果没有未使用的消息,则通过new的方式创建返回,所以使用Message.obtain()的方式来获取实例可以大大减少当有大量Message对象而产生的垃圾回收问题(减少内存抖动现象)。Message类本身是一个单向列表,sPool就是通过单向列表实现的复用池的头节点。
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Handler的使用
1.常规使用
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
//处理相关业务
}
}
};
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessageDelayed(message, 2000);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
2.弱引用方式封装
public class BaseHandler<T extends BaseHandler.BaseHandlerCallBack> extends Handler {
WeakReference<T> wr;
public BaseHandler(T t) {
wr = new WeakReference<>(t);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
T t = wr.get();
if(t != null) {
t.callBack(msg);
}
}
public interface BaseHandlerCallBack {
void callBack(Message msg);
}
}
public class MyActivity extends AppCompatActivity implements BaseHandler.BaseHandlerCallBack {
private BaseHandler<MyActivity> handler = new BaseHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
handler.sendEmptyMessage(1);
}
@Override
public void callBack(Message msg) {
if(msg.what == 1){
//处理消息
}
}
}
Handler相关面试题:Handler消息机制详解_feather(猎羽)-优快云博客
HandlerThread
使用场景
在子线程中的通过Handler接收处理耗时任务,或者说是为了取代下面的这种写法。另外IntentService的实现就是利用了HandlerThread。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// 这里处理消息
}
};
Looper.loop();
}
原理
HandlerThread本质是一个线程,继承自Thread,内部有自己的Looper对象进行looper循环,将此Looper和Handler绑定,Handler发送的消息进入消息队列,此looper会不断循环读取来回调给Handler的handleMessage方法处理。
优势
- 将loop运行在子线程中处理,减轻了主线程的压力,使主线程更流畅
- 串行执行,开启一个线程起到多个线程的作用
- 有自己的消息队列,不会干扰UI线程
劣势
- 由于每一个任务队列逐步执行,一旦队列耗时过长,消息延时
- 对于IO等操作,线程等待,不能并发
源码
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
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;
}
}
使用案例
public class MainActivity extends AppCompatActivity {
TextView tv;
Handler handler;
HandlerThread mHandlerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tv);
mHandlerThread = new HandlerThread("handler-thread");
mHandlerThread.start();
handler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("name="+Thread.currentThread().getName()+";msg="+msg.what);
}
};
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = Message.obtain();
msg.what = 22;
handler.sendMessage(msg);
}
});
new Thread(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessage(33);
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
}
IntentService
IntentService 是 Service 的子类,默认为我们开启了一个工作线程,使用这个工作线程逐一处理所有启动请求,在任务执行完毕后会自动停止服务,使用简单,只要实现一个方法 onHandleIntent,该方法会接收每个启动请求的 Intent,能够执行后台工作和耗时操作。可以启动IntentService 多次,而每一个耗时操作会以队列的方式在 IntentService 的 onHandlerIntent 回调方法中执行,
并且,每一次只会执行一个工作线程,执行完第一个再执行第二个。并且等待所有消息都执行完后才终止服务。IntentService 适用于 APP在不影响当前用户的操作的前提下,在后台默默的做一些操作。
使用场景
在后台处理耗时任务。
原理
内部创建了一个HandlerThread和继承自Handler的ServiceHandler,将HandlerThread的looper传入ServiceHandler进行绑定。IntentService被startService的时候会调用onStartCommand生命周期,此时会发送消息到消息队列,然后被HandlerThread不断循环的looper读取并回调给ServiceHandler的handleMessage方法,然后在handleMessage方法中回调给IntentService的onHandleIntent方法来处理。
核心源码
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {//处理looper读取的消息
onHandleIntent((Intent)msg.obj);//回调给IntentService的onHandleIntent方法
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);//HandlerThread的looper和ServiceHandler绑定
}
@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);//发送消息到消息队列
}
使用案例
//1.在AndroidManefest中声明MyIntentService
//2.继承IntentService,重写onHandleIntent
public class MyIntentService extends IntentService {
public MyIntentService(){
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 模拟耗时操作
download();
}
//模拟耗时任务
private void download(){
try {
Thread.sleep(3000);
System.out.println("下载完成");
//完成后可以通过EventBus或者广播通知相关页面
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//3.开启服务
startService(new Intent(context, MyIntentService.class));
AsyncTask
在子线程处理耗时任务回调主线程刷新UI。目前已经启用,被RxJava和Kotlin的协程取代。
原理
内部主要由Handler和两个线程池组成。SERIAL_EXECUTOR是任务队列线程池,用于调度任
务,按顺序排列执行。THREAD_POOL_EXECUTOR是执行线程池,真正执行具体的线程任务。Handler用于工作线程和主线程的异步通信。当执行execute()方法的时候,其实是去调用SERIAL_EXECUTOR的execute()方法。将任务放入队尾,然后从头开始取任务调用THREAD_POOL_EXECUTOR的execute()方法依次执行,直到队列中没有任务。每个AsyncTask任务只能执行一次execute(),因为每个AsyncTask有一个状态,去execute的时候会判断他的状态,如果已经执行过了再去执行就会报错。SERIAL_EXECUTOR和THREAD_POOL_EXECUTOR线程池设计成静态的,让多个AsyncTask的实例对象可以共享这两个线程池,来形成队列。
核心源码
初始化
初始化的时候在主线程创建Handler用来回调主线程刷新UI。WorkerRunnable mWorker实现了Callable接口,在call中做耗时任务doInBackground,再将mWorker放入FutureTask用于丢给线程池去执行。
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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);
}
}
};
}
两个线程池
SERIAL_EXECUTOR线程池维护一个有序队列,为了让任务串行执行,真正去执行任务的是THREAD_POOL_EXECUTOR线程池。
//这个线程池里面有一个有序队列,异步任务会在这里排队有序输出到THREAD_POOL_EXECUTOR线程真正执行
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//将异步任务存入mTasks
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
//如果没有任务正在被执行,就取一个队首的任务丢入THREAD_POOL_EXECUTOR线程池去真正执行
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 20;
//真正去执行任务的线程池
public static final Executor THREAD_POOL_EXECUTOR;
//SynchronousQueue表示这个等待队列没有容量,核心线程容量为1,那么当核心线程数量满了的时候就会使用非核心线程去执行任务,当达到最大线程数时就会执行拒绝策略
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), sThreadFactory);
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
执行方法
execute()用于执行串行任务
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) 用于并发执行
//串行执行,先进入SERIAL_EXECUTOR线程池中的队列排队等待进入THREAD_POOL_EXECUTOR线程池去真正执行
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
//传入去执行线程池,我们异步跑任务一般使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
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;
}
使用
三个泛型参数分别是参数类型,进度类型,结果类型。
AsyncTask<Params, Progress, Result>
AsyncTask<Integer, Integer, String> asyncTask = new AsyncTask<Integer, Integer, String>() {
@Override
protected String doInBackground(Integer... integers) {
publishProgress(0);//发个消息回调给onProgressUpdate
//做耗时任务,在子线程
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "总数量:" + 10;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//子线程处理过程中回调主线程做一些UI展示,如下载进度刷新
System.out.println(values[0]);
}
@Override
protected void onPostExecute(String value) {
super.onPostExecute(value);
//得到doInBackground的结果,当前在主线程,可以做UI刷新
System.out.println(value);
}
};
asyncTask.execute();//串行执行,会进入SERIAL_EXECUTOR线程池中的队列,并排在队尾。每次只从SERIAL_EXECUTOR的队列中取一个队首的任务放入THREAD_POOL_EXECUTOR线程池去执行,等这个任务执行完才会再来取下一个任务
//asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//直接放入THREAD_POOL_EXECUTOR线程池并发执行