Handler的使用
android.os.Handler主要用于子线程发送的数据,并用此数据配合主线程更新UI。(在子线程中更新UI会报错)
由于Handler运行在主线程中,它与子线程可以通过Message对象来传递数据,我们就可以将数据放入Message中,把这些消息放入主线程队列中,之后在主线程进行更新UI。
Handler工具类在多线程中有两方面的应用
- 在不同的线程中发送消息。
- 在未来执行某个任务。
Handler类包含如下方法:
void handleMessage(Message msg): 处理消息的方法,通常被重写用于处理消息。
final boolean hasMessages(int what): 检查消息队列中是否包含what属性为指定值的消息。
final boolean hasMessages(int what, Object object): 检查消息队列中是否包含what属性为指定值得消息且object属性为制定对象的消息。
sendEmptyMessage(int what): 发送一个空的消息。
sendMessageEmptyDelayed(int what, Long delayMillis):指定多少毫秒后发送空消息
sendMessage(Message msg): 发送一个消息。
sendMessageDelayed(Message msg, Long delayMillis):指定多少毫秒后发送消息
sendMessageAtTime(Message msg, Long delayMillis): 未来某一时间发送消息。
post(Runnable): 提交计划任务马上执行。
postAtTime(Runnable, long):提交任务在未来某一时间发送消息。
postDelayed(Runnable, long): 提交任务延迟多少毫秒提交。
PS:
1. handler在使用过程中可能会发生内存泄露,其中之一的方法就是使用removeCallbacks()方法将线程对象在队列中移除。
2. sendEmptyMessage、sendMessageEmptyDelayed、sendMessage、sendMessageDelayed这四个方法的本质都是执行了sendMessageDelayed方法。将delayMillis赋值为0可以立即发送,将what转换成msg.what可以将sendMessageEmptyDelayed转换成sendMessageDelayed方法,具体可以参考Handler的源代码。
异步消息处理机制
Android中的异步消息处理主要由四个部分组成,Message、Handler、MessageQueue、和Looper。
下面对其余三个部分进行简要介绍:
1. Message
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同的线程之间交换数据。
a. 使用arg1和arg2字段来携带一些整型数据。
b. 使用obj字段携带一个Object对象。
c. what字段是用户自定义的消息代码,这样接受这可以了解这个消息的信息。例如在子线程中令message.what = 1在handlerMessage方法中判断如果message.what ==1则text.setText(“helloworld”);
d. 其他信息可通过Bundle进行传递。
PS:Message可以通过new Message构造来创建一个新的Message,但是这种方法不建议使用,而建议使用message.obtain()来获取Message实例。因为message.obtain()是通过message池来获取实例的从而避免创建对象,从而减少内存消耗。
2. MessageQueue
MessageQueue顾名思义是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
3. Looper
Looper是每一个线程中的MessageQueue的管家。程序创建Looper对象时,会在它的构造器中创建MessageQueue对象。调用Looper的loop()方法后就会进入到一个无限循环当中,每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMeaage()方法中。每个线程只会有一个Looper对象。
异步消息处理流程分析:
首先在主线程当中创建一个Handler对象,并重写handlerMessage()方法。然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。之后这条消息会被添加到一个MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后发回到Handler的handlerMessage()方法中。由于Handler实在主线程中创建的,所以此时handlerMessage()方法中的代码也会在主线程中运行,这就可以进行UI操作了。
流程示意图如下图所示(出自郭霖《第一行代码》,侵删).
示例:
当点击按钮时滚动条每秒自增长,当滚动条满时隐藏
public class MainActivity extends Activity implements View.OnClickListener {
private Button changeButton;
private ProgressBar progressBar;
private Runnable update;
private Handler handler;
private void init(){
changeButton = (Button)findViewById(R.id.change_button);
progressBar = (ProgressBar)findViewById(R.id.progress);
changeButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
handler = new Handler(){
@Override
public void handleMessage(Message msg){
progressBar.setProgress(msg.arg1);
handler.post(update);
//如果进度条满则将线程对象在队列中移除,并且进度条取消显示
if (msg.arg1 == 100){
handler.removeCallbacks(update);
progressBar.setVisibility(View.GONE);
}
}
};
update = new Runnable() {
int i = 0;
@Override
public void run() {
i += 10;
Message msg = handler.obtainMessage();
msg.arg1 = i;
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendMessage(msg);
}
};
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.change_button:
//将进度条设为可见
progressBar.setVisibility(View.VISIBLE);
handler.post(update);
}
}
}
xml文档:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/change_button"
android:text="change"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progress"
android:max="100"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
参考:
《第一行代码》作者:郭霖。
详解Android Handler的使用。
Android Handler Message总结
android的消息处理机制(图+源码分析)——Looper,Handler,Message
博客内容是我阅读以上资料加上自己的理解所得,有部分摘抄自以上资料,侵删。