1.handle的消息传递机制
安卓的UI线程不是安全的,为了解决这个问题,安卓指定了:只允许UI线程修改UI
而handle消息传递机制就是另外一种形式的“事件处理”机制,就像各个系统处理进程似的,新启动的线程,可以通过handle传递机制来修改UI界面的值或UI了。
2.handle 介绍:
在新启动的线程中发送消息;然后再主线程中获取并处理消息。
为了解决何时发送何时处理,只能通过回调的方式来实现。
当我们重写了handle类中处理消息的方法(handleMeaage()),然后在新启动的线程中发送消息时,消息会被送到与之关联的MessageQueue,而handle则会不断的从MessageQueue中取出并处理这些消息(这时回调)。
handle类中有这些用于处理,发送消息的函数:
- void handleMessage(Message msg):处理消息的回调方法,通常在handle声明后重写;
- final boolean hasMessages(int what):检索MessageQueque队列中是否包含有参数中的值所对应的Message;
- final boolean hasMessages(int what,Object object):检索MessageQueque 队列中是否有参数what和对象object所对应的Message;
- sendEmptyMessage(int what):发送空消息,可以指定message中的what值(ps我认为就不算empty);
- final boolean sendEmptyMessageDelayed(int what,long delayMilis):延迟多少秒后发送空消息。
例子:使用Timer在新起的线程中定时发送handle消息来动态修改ImageView中的图片资源
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
ImageView imageView;
int[] number={
R.mipmap.ic_surface,
R.mipmap.ic_surface2
};
int currentInamgenumber=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.imageView=(ImageView)findViewById(R.id.imageView);
final Handler myhandle=new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==0x1){ //如果发送的消息是0x1
imageView.setImageResource(number[currentInamgenumber++%number.length]);//则动态修改图片资源
//currentInamgenumber余上总数。当当前数为数组长度时,余数为0
}
}
};
new Timer().schedule(new TimerTask() {
@Override
public void run() {
myhandle.sendEmptyMessage(0x1);//发送what值为0x1的Message
}
},0,2400);
}
}
handle的工作原理:
一:与handle一起工作的组件:
- Message:handle用于发送和接收的消息对象。
- looper:每个线程只能拥有一个looper,它的loop方法负责读取MessageQueue中的消息,读到消息之后把消息交给发送该消息的Handle来处理。
- MessageQueue:消息池,采用先进先出方式来管理消息队列。当创建looper对象时,会在他的构造器中创建MessageQueue对象,而因为looper的构造方法是由private修饰的,所以程序员无法使用looper的构造器来创建looper对象。直接使用即可(在代码处直接写looper.prepare()准备和looper,loop()启动接收消息)
对于handle,它有两个作用,那就是既接收处理消息,也发送消息。由handle发送的消息必须送到这个handle的MessageQueue中,所有在线程中必须得有一个MessageQueue,不然就没地方保存了。MessageQueue又是由Looper来创建管理,所有要想Handle正常工作,就得在线程中拥有一个looper对象。下面列出在两种情况中保证拥有looper:
- 在UI线程中,系统已经初始化了一个looper对象,所有我们可以直接创建Handle并使用。
- 在我们自己启动的新线程中,必须自己创建一个looper对象,并启动。(创建looper对象直接调用looper类的方法prepare()就可以)
接着调用looper类的loop()方法来启动looper。loop()是一个死循环,它不断的从MessageQueue中消息,并且发送给发送该条消息的Handle来处理。
二:总结
- looper:每个线程有且只能有一个looper对象。looper对象构造方法中会创建MessageQueue消息池。looper用于分发MessageQueue中的消息
- MessageQueue:采用先进先出的方式管理Message队列。有Looper对象来创建和管理
- Handle:发送和处理消息。发送是指发送给Looper管理的MessageQueue消息池。处理是指处理由looper分发的消息。
三:在线程中使用Handler的步骤:
- 调用Looper的prepare()方法为新启动的线程创建Looper对象。looper对象会在构造器重创建MessageQueue消息池
- 创建Handler子类的实例。重写handleMessage(Message msg)方法来处理来自其他线程的消息。
- 调用Looper的Loop()方法来循环分发处理MessageQueue队列中的消息。
我认为handle写在UI线程。方便,然后在新线程中调用这个handle的send方法来发送消息。而handle会在UI线程中处理这个消息并更改UI。