您的位置:首页 > 移动开发 > Android开发

Android的消息机制

2016-04-06 11:00 609 查看
    Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。在分析之前,我们先看一段错误的代码。

   

public class MainActivity extends Activity implements View.OnClickListener {

private TextView stateText;
private Button btn;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
stateText = (TextView) findViewById(R.id.tv);
btn = (Button) findViewById(R.id.btn);

btn.setOnClickListener(this);
}

@Override
public void onClick(View v) {
new WorkThread().start();
}

//工作线程
private class WorkThread extends Thread {
@Override
public void run() {
//......处理比较耗时的操作

//处理完成后改变状态
stateText.setText("LYJ的IT生活");
}
}
}
    这个程序运行会报错。原因在于,Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。既然这样,我们就在子线程中通知主线程,让主线程做更新操作。那么,我们如何通知主线程呢?我们需要使用到Handler对象。

     Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。这三者实际上是一体的,只不过我们再开发过程中比较多的接触Handler而已。Handler的作用是将一个任务切换到某个指定的线程中去执行。Android 为什么要提供这个功能呢?因为Android规定访问UI只能在主线程中进行,如果在子线程中访问就会抛出异常。因此,系统之所以提供Handler,主要是为了解决在子线程中无法访问UI的矛盾。

    系统为什么不允许在子线程中访问UI呢?这是因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。那为什么系统不对UI控件的访问加上锁机制呢?缺点有两个:首先加上锁机制会让UI访问的逻辑变得更加复杂;其次锁机制会降低UI的访问效率,因为锁机制会阻塞某些线程的执行。鉴于这两个缺点,最简单且高效的方法就是采用单线程模型来处理UI操作,对于开发着来说也不麻烦,只需要通过Handler切换一下UI访问的执行线程即可。那么就看一下上面的错误代码如何通过Handler进行修改。

public class MainActivity extends Activity implements View.OnClickListener {

private static final int COMPLETED = 0;

private TextView stateText;
private Button btn;

private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == COMPLETED) {
stateText.setText("LYJ的IT生活");
}
}
};

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
stateText = (TextView) findViewById(R.id.tv);
btn = (Button) findViewById(R.id.btn);

btn.setOnClickListener(this);
}

@Override
public void onClick(View v) {
new WorkThread().start();
}

//工作线程
private class WorkThread extends Thread {
@Override
public void run() {
//......处理比较耗时的操作

//处理完成后给handler发送消息
Message msg = new Message();
msg.what = COMPLETED;
handler.sendMessage(msg);
}
}
}
   这样通过Handler我们就可以解决线程安全的问题,把复杂的任务处理工作交给子线程去完成,子线程通过handler对象告知主线程,由主线程更新UI。

    Handler的工作需要Looper,没有Looper的线程就会报错。那么如何为一个线程创建Looper呢?其实很简单,通过Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.loop()来开启消息循环。Handler的作用是把消息加入特定的Looper所管理的消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper对象创建。

 

class myThread extends Thread {
public Handler mHandler;

public void run() {
Looper.prepare();

mHandler = new Handler() {
public void handleMessage(Message msg) {
// 处理收到的消息
}
};

Looper.loop();
}
}
    为什么前边的示例中,我们怎么没有看到Looper.prepare()和Looper.loop()的调用呢?原因在于,我们的Activity是一个UI线程,运行在主线程中,Android系统会在Activity启动时为其创建一个消息队列和消息循环。

     下面两张图是我从网上找的消息机制中几个重要成员的关系图:

   




    看这上面的两张图,我们来解释一下子线程如何把消息放入主线程的消息队列中?只要Handler对象以主线程的Looper创建,那么当调用Handler的sendMessage方法,系统就会把消息放到主线程的消息队列,并且将会在调用handleMessage方法时处理主线程消息队列中的消息。Handler对象管理的Looper对象是线程安全的,不管是添加消息到消息队列还是从消息队列中读取消息都是同步保护的。所以,不管多个子线程访问主线程的Handler对象,发送消息和处理消息的过程中数据都是一致。

   理解Android的消息机制对我们以后的程序应用开发起到很重要的作用。一定要深入理解!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android 消息机制