零、前言
Handler也是个磨人的小妖精,一次又一次的败给她,现在总结一下用法
Handler最主要的作用就是子线程更新UI的问题。
Handler使用并不难,背后的一套机制理解起来怪麻烦,而且很重要。
一、还是以最经典的:子线程更新UI来引入吧
场景:点击按钮新建线程,在新线程里更改TextView的值,如下图
1、准备工作:
public class HandlerActivity extends AppCompatActivity {
private static final String TAG = "HandlerActivity";
@BindView(R.id.id_tv_handler)
TextView mIdTvHandler;
@BindView(R.id.id_btn_change)
Button mIdBtnChange;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
ButterKnife.bind(this);
Log.e(TAG, "onCreate: " + Thread.currentThread().getName());//main
}
@OnClick(R.id.id_btn_change)
public void onViewClicked() {
//新建线程
new Thread() {
@Override
public void run() {
Log.e(TAG, "onViewClicked: " + Thread.currentThread().getName());//Thread-24375
mIdTvHandler.setText("你身上有米粒!");//更改视图
}
}.start();
}
}
2.结果:
看起来不太好,直接崩了,报了个CalledFromWrongThreadException:只有创建视图层的那个原始线程(main)才给摸他的视图。
是啊,我穿(main线程)的衣服(View)凭什么给你(其他线程)乱摸(修改...),你又不是我女朋友。
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
二、Handler的使用
人家(其他线程)就是看你衣服上有个米粒,想把他拿掉,你(main线程)还不乐意了。好吧,我找你女友(Handler)去,让她把你拿掉
public class HandlerActivity extends AppCompatActivity {
private static final String TAG = "HandlerActivity";
@BindView(R.id.id_tv_handler)
TextView mIdTvHandler;
@BindView(R.id.id_btn_change)
Button mIdBtnChange;
//新建Handler
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String info = (String) (msg.obj);
//更新UI
mIdTvHandler.setText(info);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
ButterKnife.bind(this);
}
@OnClick(R.id.id_btn_change)
public void onViewClicked() {
new Thread() {
@Override
public void run() {
//拿到一个Message对象--或直接new,但不建议new。Message.obtain()使用享元模式
Message msg = Message.obtain();
//将数据放到信息里
msg.obj = "你身上有米粒!";
//发送消息
mHandler.sendMessage(msg);
//或者
//msg.obj = "你身上有米粒";
////使用handler.obtainMessage获得的msg 可以直接msg.sendToTarget()
//msg.sendToTarget();
}
}.start();
}
}
二、发送空消息
1.空消息
1-1:空消息要有一个标识
private int SEND_ID = 0;
1-2:发送空消息:
new Thread() {
@Override
public void run() {
mHandler.sendEmptyMessage(SEND_ID);
}
}.start();
1-3:Handler根据接收的标识执行动作
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == SEND_ID) {
mIdTvHandler.setText("你身上有米粒!");
}
}
};
2.延迟空消息
mHandler.sendEmptyMessageDelayed(SEND_ID,1000);
//或:mHandler.sendEmptyMessageAtTime(SEND_ID, SystemClock.uptimeMillis()+1000);
3.同样sendMessage延迟类似:
mHandler.sendMessageDelayed(msg, 1000L);
mHandler.sendMessageAtTime(msg, SystemClock.uptimeMillis()+1000);
三、post发送消息:传入Runnable
通过mHandler反复发信息可做到循环
mRunnable = new Runnable() {
@Override
public void run() {
index++;
mIdTvHandler.setText("你身上有"+index+"個米粒");
if (index < 10) {
mHandler.postDelayed(this, 2000);
}
}
};
new Thread(){
@Override
public void run() {
mHandler.postDelayed(mRunnable, 2000);
}
}.start();
移除callback
if (mRunnable != null) {
mHandler.removeCallbacks(mRunnable);
}
四、Activity方法:runOnUiThread
可见底层也是基于Handler机制的
new Thread(){
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mIdTvHandler.setText("你身上有米粒!");
}
});
}
}.start();
五、Handler和Timer结合
public class HandlerTimerActivity extends AppCompatActivity {
private static final String TAG = "HandlerActivity";
@BindView(R.id.id_tv_handler)
TextView mIdTvHandler;
@BindView(R.id.id_btn_change)
Button mIdBtnChange;
private final Timer timer = new Timer();
private TimerTask task;
int count = 0;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mIdTvHandler.setText("你身上有" + count + "個米粒!");
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
ButterKnife.bind(this);
}
@OnClick({R.id.id_tv_handler, R.id.id_btn_change})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.id_tv_handler:
timer.cancel();
break;
case R.id.id_btn_change:
task = new TimerTask() {
@Override
public void run() {
mHandler.sendEmptyMessage(0);
count++;
}
};
timer.schedule(task, 2000, 3000);
break;
}
}
}
后记、
1.声明:
[1]本文由张风捷特烈原创,转载请注明
[2]欢迎广大编程爱好者共同交流
[3]个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
[4]你的喜欢与支持将是我最大的动力
2.连接传送门:
更多安卓技术欢迎访问:安卓技术栈
我的github地址:欢迎star
简书首发,腾讯云+社区同步更新
张风捷特烈个人网站,编程笔记请访问:http://www.toly1994.com
3.联系我
QQ:1981462002
邮箱:1981462002@qq.com
微信:zdl1994328