【Android 源码分析】Android 线程消息机制深入分析

原文地址:http://blog.csdn.net/hjpdyxhjd ... 66711

1 简介

Android线程消息机制是本文所要讨论的内容,在此之前我们需要先简单介绍下(之后会详细说明)线程消息机制中的四个主要成员,它们分别是Looper、Handler、Message和MessageQueue:
  • Looper是消息循环处理器,它负责从MessageQueue(消息队列)中提取一个Message对象进行处理。
  • Handler是消息发送者,它负责将Message发送到MessageQueue中等候被处理。
  • Message是消息载体,其内部保存了由我们定义的要被处理的业务逻辑以及相关的数据。
  • MessageQueue是消息队列,Handler将Message发送到消息队列中,消息队列负责维护这些待处理的Message。

接下来让我们来看看Looper、Handler、Message和MessageQueue之间是如何协同工作构建起消息循环机制的,具体步骤如图1:
  1. Handler向MessageQueue发送消息Message,发送的消息并不会马上被执行,而是在队列中等待。
  2. MessageQueue负责维护Message,当Looper要从MessageQueue中提取一个Message的时候,MessageQueue会按照一定规则弹出一个Message。
  3. Looper进行死循环操作,从MessageQueue中不断提取Message进行处理。

Handler Digram

2 简单示例

在开发中经常会遇到多线程操作,最常见的情况是子线程要修改主线程(也叫做UI线程)中的UI(例如子线程进行下载任务,更新主线程的进度条),这时候子线程必须通过线程消息机制来向主线程发送更新UI的消息,主线程在接收到更新消息之后才更新UI,而不能通过子线程直接去操作主线程里的UI(例如直接操作ProgressBar)。

下面是一个简单的示例,Activity里有一个Progress Bar,我们先开一个线程模拟耗时操作(比如下载文件),由于子线程是不能够直接修改主线程UI的,所以我们必须通过消息机制来完成进度条的更新操作,具体的代码如下:

public class MainActivity extends ActionBarActivity {

    private ProgressBar mPbTest;

    //定义一个Handler内部类,并且重写handleMessage(Message msg)方法更新进度条,
    //handleMessage(Message msg)是在主线程中被调用的,所以可以修改UI的。
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mPbTest.setProgress(msg.arg1);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mPbTest = (ProgressBar) findViewById(R.id.pbTest);
    }

    @Override
    protected void onStart() {
        super.onStart();

        //开启子线程模拟耗时操作,但是子线程是不能直接更新UI线程的进度条的,所以需要用Handler
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i <= 100; i++) {
                    Message msg = mHandler.obtainMessage();
                    msg.arg1 = i;
                    mHandler.sendMessage(msg);
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}


这是一个很常用的异步更新UI的方式,但是这种方式存在着内存泄露的风险,在文章的最后我们再来说明为什么会有这个问题,并且给出一个解决方案,不过接下来我们先具体介绍一下线程消息机制的用法。

努力搬运中...
1 分享
ask

要回复文章请先登录注册