ps:这是关于Android Handler 机制的第一篇文章,主要来讲一下Handler的用法,本文尽可能概括彻底,若有缺漏,欢迎补充。java
Handler的主要做用是切换线程,以及隐式的充当接口回调的做用,当子线程网络请求结束后,经过handler发送消息给主线程,这一点都很少说了。web
先来贴一种最经常使用的用法:数组
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//...处理逻辑
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(MainActivity.HANDLER_MAIN_CODE);
}
});
复制代码
这种方法是你们最经常使用的,使用Handler的匿名内部类,去覆写handleMessage方法,来处理当消息到达时所作出的反应。这里埋一个伏笔:markdown
这里IDEA在提示可能会发生内存泄漏,具体为何会发生内存泄漏,针对问题的具体分析以及最后封装SafeHandler,我会在第三篇Handler文章中讲述。网络
先看一下Message,Message用来承载数据,承载数据的实现是Message的几个public的成员变量:ide
public int what;
public int arg1;
public int arg2;
public Object obj;
复制代码
另外Message还提供了经过Bundle来传递数据: Bundle也是一个数据载体,这里就很少说了。函数
/** * Like getData(), but does not lazily create the Bundle. A null * is returned if the Bundle does not already exist. See * {@link #getData} for further information on this. * @see #getData() * @see #setData(Bundle) */
public Bundle peekData() {
return data;
}
/** * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members * as a lower cost way to send a few simple integer values, if you can. * @see #getData() * @see #peekData() */
public void setData(Bundle data) {
this.data = data;
}
复制代码
Message中维持着一个Message池,因此一般咱们无需new Message(),能够调用: Message message = Message.obtain();
,节省内存空间。 。oop
Handler处理消息除了文章开头所说到的一种,其实还有两种: message的callback和handler的mCallback,一共有三种,为何我能够这么说呢?下面上源码post
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
复制代码
这个dispatchMessage()
方法是在Lopper.loop方法的无限循环中调用的:this
for(;;) {
...
msg.target.dispatchMessage(msg);
...
}
复制代码
这个msg就是咱们发送的消息,target就是咱们发送消息的handler。这里看不懂的也不要紧,毕竟涉及到源码,以后的第二篇会将。如今只须要知道这个dispathchMessage方法是在消息接收处调用的。而后继续返回去看这个方法的内部实现。 这个方法经过三层if-else嵌套,也就规定了这三种Handler处理消息的方法的优先级: 能够看到咱们经常使用的第三种方法,覆写handlerMessage是优先级最低的。
既然是msg的一个属性,那么确定是经过msg承载callback来发送出去,先看一下callback的定义
@UnsupportedAppUsage
/*package*/ Runnable callback;
复制代码
这是一个Runnable,而后看一下handler的handleCallback(msg);
方法:
private static void handleCallback(Message message) {
message.callback.run();
}
复制代码
这样咱们就知道了,消息接受处在收到message以后,若是message的callback不为空,就调用这个callback的run方法。下面看基于将事件包装成Message的Runnable的两种方法:
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Runnable runnable = new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "消息接受后执行这段代码,这段代码运行在主线程"
,Toast.LENGTH_SHORT).show();
}
};
Message message = Message.obtain(mHandler, runnable);
mHandler.sendMessage(message);
}
});
}
复制代码
相比于上一种方法,这种方法可能更加形象,将一个携带事件的Runnable,post到MesageQueue中,而后交给主线程执行:
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "这段代码交给主线程去执行", Toast.LENGTH_SHORT).show();
}
});
}
});
复制代码
这个方法其实和匿名内部类的写法大同小异,只不过是把覆写的handleMessage方法中的逻辑转移到mHandler的mCallback中,下面直接上代码:
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
Toast.makeText(MainActivity.this, "收到消息", Toast.LENGTH_SHORT).show();
return true;
}
};
private Handler mHandler = new Handler(callback);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(Message.obtain());
}
});
}
复制代码
注意handleMessage的返回时,若是返回true,那么表示处理条消息,再也不向下执行。若是返回false,那么表示没有成功处理这条消息,接着向下执行,也是就执行Handler的handleMessage方法
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
Toast.makeText(MainActivity.this, "收到消息", Toast.LENGTH_SHORT).show();
//...处理消息
if (...) {
return false;
}
return true;
}
};
private Handler mHandler = new Handler(callback) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this,
"若是callback的handleMessage返回false,那么接着执行这里"
, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(Message.obtain());
}
});
}
复制代码
这样终于把Handler的三种处理消息的用法搞清楚了,须要注意的是,第一种方法和其余两种是互斥的,只要Message的callback不为空,那么就执行callback中的run方法的逻辑,而不会执行handleMessage。
咱们须要知道的是,Handler机制在Android中的做用绝对不单单是给开发者切换线程,Handler机制在维持一个APP的正常运做。一个点击事件,启动一个Activity等等基础功能,都离不开Handler。具体是如何运做的,就要看Handler机制的源码了。
既然都看完了,你们点个赞再走呀