Android开发中Handler的简单用法
背景
在写自己的小项目快汇-一个简单的汇率转换工具时,其中有一个功能点是监听点击按钮事件之后发送获取汇率的网络请求,并刷新界面中的RecyclerView。调试报错,研究了一下是典型的子线程刷新UI导致报错。
Only the original thread that created a view hierarchy can touch its views.
在安卓中,一般情况下子线程是不能刷新UI的,这是为了提高移动端更新UI的效率和安全性。
Android的UI访问是没有加锁的,多个线程可以同时访问更新操作同一个UI控件。也就是说访问UI的时候,android系统当中的控件都不是线程安全的,这将导致在多线程模式下,当多个线程共同访问更新操作同一个UI控件时容易发生不可控的错误,而这是致命的。所以Android中规定只能在UI线程中访问UI,这相当于从另一个角度给Android的UI访问加上锁,一个伪锁。
引用自 为什么不能在子线程中更新UI
解决办法
有很多办法可以通过子线程和主线程通信的方式来让子线程“通知”主线程需要刷新UI了。这里用一种最简单的方法,Android SDK中的Handler。
首先new一个Handler对象:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
};
接着在需要更新UI的子线程代码处new一个Message对象与主线程通信:
//业务代码
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
List<String> rate_final = new ArrayList<>();
String[] rate_split = result.split("\"rate\"");
int size = rate_split.length;
for (int i = 1; i < 10; i++) {
rate_final.add(rate_split[i].substring(2, 8));
}
Log.d("a", "a");
for (int i = 0; i < 9; i++) {
Current.remove(i);
if (rate_final.get(i).equals("1\",\"up")) {
Current.add(i, "1");
} else {
Current.add(i, rate_final.get(i));
}
}
//new一个message
Message message = handler.obtainMessage();
message.what = 1;
handler.sendMessage(message);
}
message的what值为1。
这样当Handler接收到Message之后,通过if语句判断what值,若为1则说明是我们刚才定义的那条消息:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
exchangeListAdapter.notifyDataSetChanged();
}
}
};
执行我们刷新UI的逻辑:
exchangeListAdapter.notifyDataSetChanged();
这是让RecyclerView的适配器刷新数据的代码。
结语
子线程刷新UI是一个常见的需求,如果能正确合理的使用,就可以避免线程冲突,让程序高效正确地执行。