版权声明:本文为博主原创文章,未经博主允许不得转载。
PS:转载请注明出处
作者: TigerChain
地址: http://www.jianshu.com/p/73e5fd7eb7da
本文出自 TigerChain 简书 Android 系列
教程简介
- 1、阅读对象
本篇教程适合新手阅读,老手直接略过
-
2、教程难度
初级
正文
摘要:
Handler 在 Android 的作用主要是线程间通讯的,现在也有各种文章在讲解 Handler 的作用以及源码分析,但是必定这些都是别人自己的总结和整理,和自己总结还是有区别的,为了加深自己的记忆所以自己也来分析一下 Handler 以及它的小伙伴们。
什么是 Handler
什么是 Handler?
再华丽的解释也不过是官方的解解释吧:先看官网上的一段话
A Handler allows you to send and process Message and Runnable objects associated with
a thread's MessageQueue. Each Handler instance is associated with a single thread
and that thread's message queue. When you create a new Handler, it is bound to the
thread / message queue of the thread that is creating it -- from that point on,
it will deliver messages and runnables to that message queue and execute them
as they come out of the message queue.
大概意思就是 Handler 可以发送 Message 和 Runnable 对象发送到 Handler 所关联的线程队列中去,每个 Handler 的实例都会绑定到创建它的线程中。
Handler 的作用
再来看官网杂说的
There are two main uses for a Handler:
(1) to schedule messages and runnables to be executed as some point in the future
(2) to enqueue an action to be performed on a different thread than your own.
大概意思就是说,Handler 有两个用途:
(1)、在某一时刻执行某些事情
(2)、在不同的线程中执行操作 (也就是线程间通信)
Handler 常用的方法
方法名 | 描述 |
---|---|
boolean post (Runnable r) | 立即执行操作 |
postAtTime(Runnable, long) | 在指定的时间执行某些操作 |
postDelayed(Runnable, long) | 延时执行某些操作 |
sendEmptyMessage(int) | 发送一个含有what的信息 |
sendMessage(Message) | 发送一个Message |
sendMessageAtTime(Message, long) | 在指定的时间发送消息 |
sendMessageDelayed(Message, long) | 延时发送消息 |
Handler 默认是运行在 UI 线程中的,默认默认默认...哦 一定记得,至于为什么,我们后面会说的。
Handler 常用的使用方式
1、解决 ANR,子线程更新UI线程
在Android应用程序中我们最常见的异步莫过于 ANR 了(主线程执行耗时操作了,发起网络请求,或操作 IO 等),通常情况下在 Activity 是5秒钟响应就会报这个错,在 BroadCast 中是 10 秒钟,使用 Handler 可以很容易的解决这个问题。
解决方法:
- 1、定义 Handler 并重写 handleMessage 方法
//在UI线程中
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
//取得传递过来的 msg
String passedChangeTv = (String) msg.obj;
tv.setText(passedChangeTv);
break ;
}
}
} ;
- 2、在子线程中去执行耗时操作
//比如请求服务器,然后更新 TextView
new Thread(new Runnable() {
@Override
public void run() {
//执行耗时操作
/**
* 1 请求服务器
* 2 解析数据
* 3 获取数据
*/
//比如从服务器取得的数据是" Handler 应用"
String changeTv = "Handler应用" ;
Message message = new Message() ;
message.what = 1 ;
message.obj = changeTv ;
mHandler.sendMessage(message) ;
}
}).start();
这样就可以解决 ANR
2、可以用作轮询,或是定时器
- 1、举个栗子,我们要一秒钟打印一个字符串,我们可以使用 Handler 的 postDelayed 方法
private Handler mtimeTaskHandler = new Handler() ;
private void timerTaskHandler() {
//调用Handler自带的
mtimeTaskHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.e("===","TAG:"+ System.currentTimeMillis()/1000) ;
mtimeTaskHandler.postDelayed(this,1000) ;
}
},1000) ;
}
- 2、一秒钟请求一次服务器,然后把服务器的最新数据显示在 TextView ,在这里我们使用 Handler 的sendMessageDelayed(Message msg,Long deayTime)方法
private Handler preSecondHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
//取得传递过来的 msg
int passedChangeTv = (int) msg.obj;
tv.setText(passedChangeTv+"");
//再次调用获取服务器最新数据方法
preSecondGetServer() ;
break ;
}
}
} ;
private int i ;
private void preSecondGetServer() {
new Thread(new Runnable() {
@Override
public void run() {
//假设这里从服务器取回来的 i
i++ ;
Message message = new Message() ;
message.what = 1 ;
message.obj = i ;
preSecondHandler.sendMessageDelayed(message,1000) ;
}
}).start();
这样就可以一秒请求一次服务器,并且把结果显示在 TextView 上了
3、两个子线程进行通信
Handler的作用就是是进行线程间通信的,上面说的都是UI线程(主线程)和子线程之间的通信,那么两个工作线程(子线程)可以通信吗,答案是肯定 的。
- 1、先声明 Handler 所在的线程
//成员变量 子线程中的 Handler
private Handler threadHandler ;
class MyThread extends Thread{
{
//一实例化就开启线程 代码块
start();
}
@Override
public void run() {
super.run(); // Handler 所在的线程默认是没有 looper 的(除了 Activity )
Looper.prepare();
threadHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//取得传递过来的 msg
String passedChangeTv = (String) msg.obj;
//设置显示
tv.setText(passedChangeTv);
}
} ;
Looper.loop();
}
}
注意:子线程默认是没有 Looper 的所以我们在子线程中一定要声明 Looper.prepare() 和 Looper.loop() 在它们之间去初始化 Handler
- 2、在另一个子线程中发送消息
private void threadHandlerTask() {
new Thread(new Runnable() {
@Override
public void run() {
String changeTv = "Handler应用" ;
Message message = new Message() ;
message.what = 1 ;
message.obj = changeTv ;
threadHandler.sendMessage(message) ;
}
}).start() ;
}
- 3、最后在合适的地方调用,在这里我们为了演示就在 Activity 的onCreate() 方法中调用
MyThread t = new MyThread() ;
threadHandlerTask() ;
以上就完成了两个子线程通过 Handler 来通信。
注意:上面的子线程能信有问题,不知道细心的朋友发现了没有,我故意留了一个 bug,忽略此 bug 不提,我们上面的程序性能是有问题的,我们一一解决。
1、上面代码存在的 bug
细心的朋友会说我靠,擦,FK,竟然在子线程中更新 UI,我们要以清楚的看到 threadHandler 是在子线程中的,那么我们是不能更新 UI的。会 ANR 的好不好呀,没错就是这个问题,不怕,程序员就是发现问题并解决问题的,我们来解决这个问题,修改代码如下。
- 1、首先在 MainActivity 中声明一个 threadHander( threadHander 一定是在主线程中的)
private Handler threadHander = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//取得传递过来的 msg
String passedChangeTv = (String) msg.obj;
tv.setText(passedChangeTv+"");
}
} ;
所以上面代码是可以更新 UI 的没有问题
- 2、声明子线程
class MyThread extends Thread{
private Looper mLooper ;
private Handler mHandler ;
/**
* 代码块或是构造方法中开启线程都可以
*/
public MyThread(){
Log.e("t所在的线程",this.getName()) ;
start();
}
// {
// //一实例化就开启线程 代码块
// start();
// }
@Override
public void run() {
super.run(); // Handler 所在的线程默认是没有 looper 的(除了Activity)
Looper.prepare();
mLooper = Looper.myLooper() ;
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//取得传递过来的 msg
String passedChangeTv = (String) msg.obj;
//设置显示 这里的 Handler 运行在子线程中去的,所以不能更新UI
// tv.setText(passedChangeTv);
threadHander.sendMessage(threadHander.obtainMessage(1,passedChangeTv)) ;
}
} ;
Looper.loop();
}
public Handler getThreadHandler(){
return mHandler!=null?mHandler:null ;
}
}
- 3、在另一个线程中去发送消息
private void threadHandlerTask() {
new Thread(new Runnable() {
@Override
public void run() {
String changeTv = "Handler应用" ;
Message message = new Message() ;
message.what = 1 ;
message.obj = changeTv ;
t.getThreadHandler().sendMessage(message) ;
}
}).start() ;
}
此处的t就是 MyThread 的实例,声明成成员变量,不用纠结
我们来捋一捋流程,首先调用
t.getThreadHandler().sendMessage(message)
将消息发送到 MyThread 的 Handler 中,然后在 MyThread 的 Handler (子线程中)中将消息发送到 MainActivity 的 threadHander(UI线程中),这样就完成了,子线程更新UI线程的过程
注:这里是为了显示更新UI线程所以多次发送,如果只是为了两个线程间通信,那么 threadHander 是可以不需要的
我们把改后的代码运行一下,并且我添加了一些线程的日志,看效果
从图中我们可以看到,子线程间通信是完全没有问题的,但是我们退出应用再进入应用的时候发现,线程数量在不停的增加,我靠如果打开 100 次岂不是又多了 100 个线程,1000... 次呢,想都不敢想。如何解决呢,往下看。
2、手动调用 Looper 需要手动释放
接着上面继续说,问题出现在那里呢,就是手动调用 Looper.perpare() 和 Looper.loop() 的时候一定要记得在任务完成以后,或是合适的地方要释放掉 looper,要调用 looper.quit(),结束消息队列,进而结束线程。如果不这么做,thread 会长时间存在不销毁这。这就是上面所说的性能问题,不断的开辟线程,线程的开辟是需要开销的,所以我们来解决这一问题
- 1、我们改造MyThread类
class MyThread extends Thread{
private Looper mLooper ;
private Handler mHandler ;
/**
* 代码块或是构造方法中开启线程都可以
*/
public MyThread(){
Log.e("t所在的线程",this.getName()) ;
start();
}
// {
// //一实例化就开启线程 代码块
// start();
// }
@Override
public void run() {
super.run(); //Handler所在的线程默认是没有looper的(除了Activity)
Looper.prepare();
mLooper = Looper.myLooper() ;
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//取得传递过来的 msg
String passedChangeTv = (String) msg.obj;
//设置显示 这里的Handler运行在子线程中去的,所以不能更新UI
// tv.setText(passedChangeTv);
threadHander.sendMessage(threadHander.obtainMessage(1,passedChangeTv)) ;
}
} ;
Looper.loop();
}
//这里是新添加的方法
public void exit(){
if(mLooper!=null){
mLooper.quit();
mLooper = null ;
}
}
public Handler getThreadHandler(){
return mHandler!=null?mHandler:null ;
}
}
我们只是在 MyThread 类中添加了一个 exit 方法,其它的都没有变.
- 2、为了方便测试,我们在 onDestory() 方法中调用
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("onDestroy",t.getName()+"销毁") ;
t.exit();
t=null ;
}
我们重新跑一下应用程序,来观察结果
从效果图中我们可以看出,当我们手动调用 Looper.prepare() 和 Looper.loop() 的时候创建一个线程,但是们退出应用的时候会退出 Looper,线程会销毁,我们需要你的时候让你存在,不需要的时候让你销毁,这就大大提高了性能。我们看始终激活的线程数量都是5,这是我们所期望的
总结:在子线程中,如果手动为其创建了 Looper,那么在所有的事情完成后应该调用 quit 方法来终止消息循环
Handler 和它兄弟们
Handler 不能单独工作,必须和它的兄弟们一起协同才可以工作。而它的兄弟们就是以下三个
1、Looper
Looper 字面意思是一个轮询器,是用来检测 MessageQueue 中是否有消息,如果有消息则把消息分发出去,没有消息就阻塞在那里直到有消息过来为止。
一个线程对应一个 Looper,一个 Looper 对应一个 MessageQueue.
注意:默认情况下,线程是没有 Looper 的,所以要调用 Looper.prepare() 来给线程创建消息队列,然后再通过,Looper.loop() 来不停(死循环)的处理消息消息队列的消息
2、MessageQueue
是用来存放消息的,通过 Looper.prepare() 来初始化消息队列。MessageQueue 从字面意思来看是一个消息队列,但是内部实现并不是基于队列的。是基于一个单链表的数据结构来维护消息列表的,链表插入和删除优势很明显。
3、Message
传递信息的载体,可以携带一些信息,类似于 Intent,Bundle 一样。两个线程通过 Message 联系在一起。
Handler 源码分析
重点来了,下面我们一起来分析一下Handler的源码
1、sendMessage() 发生了什么
当我们调用 Handler 的 sendMessage 方法的时候到底发生了什么,我们从源码去看一下
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
我们可以看到调用sendMessage方法调用sendMessageDelayed(msg, 0)
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
而 sendMessageDelayed 方法又调用 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis) 方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//取得MessageQueue
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//把消息存放到MessageQueue中
return enqueueMessage(queue, msg, uptimeMillis);
}
在这里不是不有些小激动呢,我们看到 sendMessage 最终调用的是 enqueueMessage(queue, msg, uptimeMillis) 这个方法,我们来看看这个方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
我勒个插,还在调用,这里代码我们基本上也能看懂,就是不知道msg.target 是个毛线,不过他是 Message 的一个属性,我们进去看一下发现 msg.target 是一个Handler,好我们再看queue.enqueueMessage(msg, uptimeMillis) 方法
boolean enqueueMessage(Message msg, long when) {
//msg.target 这么熟悉,我去不就是 Handler 吗,要发送一个消息肯定要有 Handler 呀,不然发个毛毛呢
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//消息是否正在使用
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//消息插入链表头,条件是如果MessageQueue为空,或是消息发送的时刻为0或者消息发送的时刻小于链表头的派发时刻,就把消息插入链表头
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//否则就找个合适的位置把消息插到链表中
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
总之这个方法就是把消息插入到消息队列中,我们现在可以归纳了,当调用handler.sendMessage方法的时候做了一件重要的事:
把消息插入到MessageQueue中
2、Looper 该上场了
根据前面所述,我们知道 Looper 的作用是创建消息队列,和处理消息。
- 1、Looper.prepare() 方法就是用来创建消息队列的,我们看源码
public static void prepare() {
prepare(true);
}
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));
}
我们看到 prepare 方法调用 prepare(true) 方法,此方法中我们目前也没有看不懂的语句,无非就是 sThreadLocal 是什么东东,不要紧,我们暂且当它是一个 List 一样用来存取 Looper 的,接下来我们看 new Looper(quitAllowed) 方法
private Looper(boolean quitAllowed) {
//初始化消息队列
mQueue = new MessageQueue(quitAllowed);
//取得当线线程
mThread = Thread.currentThread();
}
看到了吧,确实在上面方法中初始化了 MessageQueue。所以我们这里总结 Looper.prepare() 方法就是创建了一个消息队列
根据上面的分析,我们有了消息队列,也知道 sendMessage 是把消息插入到消息队列中去了,那么如何管理 MessageQueue中 的消息呢,Looper.loop() 该上场了。
- 2、Looper.loop(): 我们直接看源码
public static void loop() {
//取得Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//拿到 MessageQueue
final MessageQueue queue = me.mQueue;
...省略部分代码
for (;;) { //这里是一个死循环,取出每个消息,然后分发
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
... 省略部分代码
//msg.target(Handler)这里调用 Handler 的dispatchMessage方法
msg.target.dispatchMessage(msg);
}
}
综上代码,我们可以得出结论 Lopper.loop() 方法主要作用是取出 MessageQueue 中消息然后调用 Handler 的 dispatchMessage 方法把消息分发出去(前提是 Message 中要有消息)
接下来我们看 Handler 的 dispatchMessage 方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//如果msg.callback不为空,则调用handleCallback
handleCallback(msg);
} else { 否则,mCallback不为空
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//调用handleMessage
handleMessage(msg);
}
}
似乎看到熟悉的方法了,对就是 handleMessage(msg),就是 Handler 的回调方法,就是处理消息的方法。
这样我们大体了解到,Handler的处理流程了,大致如下:
Looper.parpare() ; //先准备好消息队列
Handler handler = new Handler(){
@Override
handleMessage(Message msg){
//如理发送过来的消息
...
...
}
}
Looper.loop() ; //是一个死循环,一直监听着 MessageQueue ,从消息队列中取消息,然后调用 handler. dispatchMessage 方法,最后调用的就是 handler 的 handleMessage(Message msg) 方法来处理消息
那么如何把消息插入到消息队列呢,就靠 Handler 的 sendMessage() 方法了,所以当调用了 Handler 的 sendMessage(),Looper.loop() 监听到 MessageQueue 中有消息,就调用 dispatchMessage 方法分发消息,最终调用 handler 的 handleMessage(Message msg) 方法来处理消息。
Handler的原理如下图所示
原创图:转载注明出处
Activity 默认有 Looper
Activity 中的 Looper 从何来
我们知道使用 Handler 的时候,Handler 一定要存在于有Looper.parpare() 和 Looper.loop() 的线程中可是我们都知道 Activity 中使用 Handler 的时候不用写 Looper.parpare() 和 Looper.loop(),但是为什么不用写有没有想过,那么我们来分析一下
Activity 所在线程也叫 UI 线程,为什么叫 UI 线程呢,其实它是通过 ActivityThread 来管理的,我们知道 Android 应用层是用 Java 开发的,那么 Java 肯定是有一个入口方法即 main 方法,main 方法到底在那里呢?
答案就是在 ActivityThread.java 中,我们来看一下源码
public final class ActivityThread {
... 省略一大坨代码
final Looper mLooper = Looper.myLooper();
//H就是一个Handler
final H mH = new H();
... 省略若干代码
private class H extends Handler {
省略一大堆
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING";
case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW";
...省略大量代码
}
}
return Integer.toString(code);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY:
...
case PAUSE_ACTIVITY:
...
break;
... 省略部分代码
case RESUME_ACTIVITY:
...
break;
case SEND_RESULT:
...
break;
case DESTROY_ACTIVITY:
...
break;
... 省略部分代码
case CREATE_SERVICE:
...
break;
case BIND_SERVICE:
...
break;
case UNBIND_SERVICE:
...
break;
... 省略又臭又长的代码
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
}
public static void main(String[] args) {
...省略部分代码
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
...省略部分代码
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
从上面代码中可以隐约的看到 Activity 的 oncreate ,onresume... Service 的 oncreate bindService 等等方法都在这里处理了,再从上面看到了 main 方法并且调用了 Looper.prepareMainLooper(); 和 Looper.loop(); 由此就知道了,为什么我们的 Activity 默认是有 Looper 的。
结论
Activity 叫 UI 线程,其实指的就是 ActivityThread,Activity 是由ActivityThread 管理启动,暂停等,并且 ActivityThread 的入口方法中开启了 Looper.prepareMainLooper() 和 Looper.loop(),所以我们的 Activity 默认就会有一个 Looper,Service 同理
Handler引起的内存泄露
引子
我们先来看一个例子
public class MainActivity extends AppCompatActivity {
private TextView tv ;
//在UI线程中
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
...
...
}
} ;
}
乍一看,好像没有什么问题,但是我告诉你,这段代码可能会存在内存泄露的,这是为什么呢?答案是非静态内存部会持有外部类的引用(Java的特性)
,在这里Handler是一个非静态的内存部类,会隐式的持有 MainActivity 的引用的。
解决办法
解决这个问题的办法就是避免使用非静态内部类。
static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
}
}
如果要操作Activity的一些对象,这里使用弱引用
static class MyHandler extends Handler {
// WeakReference to the outer class's instance.
private WeakReference<MyActivity> mOuter;
public MyHandler(MyActivity activity) {
mOuter = new WeakReference<MyActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MyActivity outer = mOuter.get();
if (outer != null) {
// Do something with outer as your wish.
}
}
}
完整的代码
public class MyActivity extends AppCompatActivity {
private MyHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new MyHandler(this);
}
@Override
protected void onDestroy() {
// Remove all Runnable and Message.
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
static class MyHandler extends Handler {
// WeakReference to the outer class's instance.
private WeakReference<MyActivity> mOuter;
public MyHandler(MyActivity activity) {
mOuter = new WeakReference<MyActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MyActivity outer = mOuter.get();
if (outer != null) {
// Do something with outer as your wish.
}
}
}
}
当然我们可以把Handler单独写到一个类中,配置 RxBus 或 EventBus来更新UI或执行某些操作,这里就介绍完了 Handler 的相关知识点了
想成为一个牛 B 的人都会点喜欢或分享的