Handler内部运转机制

原理

我们都知道,我们开启一个子线程的时候,会在子线程中使用主线程创建的Handler传递消息给主线程去处理,那么在Handler内部是怎么样的一种处理流程呢?

这里写图片描述

主要步骤为:
1. 用户启动一个应用,系统内部建立一个进程。
2. 进程启动主线程Main Thread。
3. Main Thread通过Looper建立一个消息队列Message Queue。
4. 消息队列是存在于主线程中的,在主线程中开始无限循环。
5. 每当有新的Message进来,消息队列就开始处理,如果没有,就执行return继续等待。

具体的源码解析可以参考鸿洋老师的Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系


初始化Handler

这里写图片描述

  • UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。
  • 使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。
  • 之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。
  • Looper初始化的时候会创建一个消息队列MessageQueue。

如何在子线程中启动一个Handler

Handler一般都会在主线程创建,但在子线程中也能创建Handler。入驻在子线程中建立一个 handler, 然后直接sendMessage 是会崩溃的,因为子线程建立 Handler,要在构造的时候注入主线程的 Looper,相当于在主线程中建立了一个Handler。

方法一:
new Thread(new Runnable() {
            public void run() {
                Looper.prepare();
                Handler handler = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
                    }
                };
                handler.sendEmptyMessage(1);
                Looper.loop();
            };
        }).start();
方法二:
new Thread(new Runnable() {
            public void run() {
                Handler handler = new Handler(Looper.getMainLooper()){ // 区别在这!!!!
                    @Override
                    public void handleMessage(Message msg) {
                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
                    }
                };
                handler.sendEmptyMessage(1);
            };
        }).start();

Post和sendMessage

Handler把压入消息队列有两大体系,Post和sendMessage:

post(Runnable),
postAtTime(Runnable, long)
postDelayed(Runnable, long),
sendEmptyMessage(int),
sendMessage(Message),
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。

sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。

对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。

Post

在Handler中,关于Post方式的方法有:
boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。

boolean postAtTime(Runnable r,long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。

boolean postDelayed(Runnable r,long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行
void removeCallbacks(Runnable r):从消息队列中移除一个Runnable对象。

Message

Message发送消息相关的方法有:

Message obtainMessage():获取一个Message对象。

boolean sendMessage():发送一个Message对象到消息队列中,并在UI线程取到消息后,立即执行。

boolean sendMessageDelayed():发送一个Message对象到消息队列中,在UI线程取到消息后,延迟执行。

boolean sendEmptyMessage(int what):发送一个空的Message对象到队列中,并在UI线程取到消息后,立即执行。

boolean sendEmptyMessageDelayed(int what,long delayMillis):发送一个空Message对象到消息队列中,在UI线程取到消息后,延迟执行。

void removeMessage():从消息队列中移除一个未响应的消息。

在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:

int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。

int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。

Object obj:传递一个任意的对象。

int what:定义的消息码,一般用于设定消息的标志。

对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。  

// 获取一个Message对象,设置what为1
Message msg = Message.obtain();
msg.obj = data;
msg.what = IS_FINISH;
// 发送这个消息到消息队列中
handler.sendMessage(msg);

handler.post(myRunnable)和handler.post(myRunnable,time);

post方法启动了runnbale,其实启动的线程和activity主线程是同一个线程,因为它只是运行了线程的run方法,而不是start方法。

在子线程中利用post(Runnable r)更新UI,原理和sendMessage()类似

调用post(Runnable r)不会开启一个新的线程,UI的更新是在主线程中完成的

在子线程中发送了消息到主线程的消息队列从而更新了UI


例子

使用postDelayed做一个定时器

这里写图片描述

package com.example.handler1;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
    private TextView text_view = null;
    private Button start = null;
    private Button end = null;

    //使用handler时首先要创建一个handler
    Handler handler = new Handler();
    //要用handler来处理多线程可以使用runnable接口,这里先定义该接口
    //线程中运行该接口的run函数
    Runnable update_thread = new Runnable()
    {
        public void run()
        {
            //线程每次执行时输出"UpdateThread..."文字,且自动换行
            //textview的append功能和Qt中的append类似,不会覆盖前面
            //的内容,只是Qt中的append默认是自动换行模式
            text_view.append("\nUpdateThread...");
            //延时1s后又将线程加入到线程队列中
            handler.postDelayed(update_thread, 1000);

        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        text_view = (TextView)findViewById(R.id.text_view);
        start = (Button)findViewById(R.id.start);
        start.setOnClickListener(new StartClickListener());
        end = (Button)findViewById(R.id.end);
        end.setOnClickListener(new EndClickListener());

    }
    private class StartClickListener implements OnClickListener
    {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            //将线程接口立刻送到线程队列中
            handler.post(update_thread);
        }                
    }

    private class EndClickListener implements OnClickListener
    {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            //将接口从线程队列中移除
            handler.removeCallbacks(update_thread);
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

更新进度条

这里写图片描述

package com.example.handler2;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class MainActivity extends Activity {
    private ProgressBar progress_bar = null;
    private Button start = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progress_bar = (ProgressBar)findViewById(R.id.progress_bar);
        start = (Button)findViewById(R.id.start);

        start.setOnClickListener(new StartOnClickListenr());
    }

    private class StartOnClickListenr implements OnClickListener
    {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            //让进度条显示出来
            progress_bar.setVisibility(View.VISIBLE);
            //将线程加入到handler的线程队列中
            update_progress_bar.post(update_thread);

        }
    }
    //创建一个handler,内部完成处理消息方法
    Handler update_progress_bar = new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            //super.handleMessage(msg);
            //显示进度条
            progress_bar.setProgress(msg.arg1);
            //重新把进程加入到进程队列中
            update_progress_bar.post(update_thread);
        }       
    };//不加这个分号则不能自动添加代码

    Runnable update_thread = new Runnable()
    {
        int i = 0;
        public void run() {
            // TODO Auto-generated method stub
            i += 10;
            //首先获得一个消息结构
            Message msg = update_progress_bar.obtainMessage();
            //给消息结构的arg1参数赋值
            msg.arg1 = i;
            //延时1s,java中的try+catch用来排错处理
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            //把消息发送到消息队列中
            update_progress_bar.sendMessage(msg);
            if(i == 100)
                //把线程从线程队列中移除
                update_progress_bar.removeCallbacks(update_thread);
        }       
    };

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

参考文章:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值