Android HandlerThread 解析

一.概述

什么是HandlerThread,官方的介绍如下;

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

我给大家翻译一下,大概的意思是说HandlerThread可以很方便的启动一个带有looper的线程,这个looper可以用来创建handler对象,同时别忘了start()方法也必须被调用。

首先来看看我们为什么要用HandlerThread,当我们在线程中实例化Handler的时候,必须保证当前线程中有Looper对象(主线程默认有Looper对象)。
为线程创建Looper对象的步骤如下:在线程的run()方法中先调用Looper.prepare()方法初始化,然后在run()方法最后调用Looper.loop()方法是Looper工作起来,这样我们就能保证当前线程已经创建好了Looper对象。那么我们实现Looper有没有更简单的方式呢?那就是HandlerThread。

二.实例

我们先看一个实例,效果如下:

这里写图片描述

这是子线程给主线程发送消息的一个例子

public class MainActivity extends Activity {

    private TextView textivew;
    int num = 0;
    private MyThread thread;
    private static Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textivew = (TextView) findViewById(R.id.textview);
        thread = new MyThread();
        thread.start();
    }

    public void send(View view) {
        Message msg = Message.obtain();
        msg.what = num;
        thread.handler.sendMessage(msg);
        textivew.setText("主线程向子线程发送" + num + "条消息");
        num++;
    }

    class MyThread extends Thread {
        Handler handler = null;
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            handler = new Handler() {
                public void handleMessage(android.os.Message msg) {
                    Toast.makeText(MainActivity.this, "子线程接收到了" + msg.what + "条信息", Toast.LENGTH_SHORT).show();
                }
            };
            Looper.loop();
        }
    }
}

下面我们看看如何使用HandlerThread
使用步骤:
1.创建一个HandlerThread,即创建了一个包含Looper的线程

HandlerThread handlerThread = new HandlerThread("lxn");
handlerThread.start(); //创建HandlerThread后一定要记得start()

HandlerThread的构造方法中传入一个字符串,代表线程名称。

2.获取HandlerThread的Looper对象

Looper looper = handlerThread.getLooper();

3.创建Handler,通过Looper初始化

Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit();。

下面我们用HandlerThread来实现上面的效果

public class MainActivity extends Activity {

    private TextView textivew;
    int num = 0;
    private HandlerThread thread;
    private static Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textivew = (TextView) findViewById(R.id.textview);
        thread = new HandlerThread("lxn");
        thread.start();
        handler = new Handler(thread.getLooper()){
            public void handleMessage(Message msg) {
                Toast.makeText(MainActivity.this, "子线程接收到了"+msg.what+"条信息", Toast.LENGTH_SHORT).show();
            };
        };
    }
    public void send(View view) {
        Message msg = Message.obtain();
        msg.what = num;
        handler.sendMessage(msg);
        textivew.setText("主线程向子线程发送" + num + "条消息");
        num++;
    }
}

源码分析

public class HandlerThread extends Thread {
    //当前线程优先级
    int mPriority;
    //线程id
    int mTid = -1;
    //Looper对象
    Looper mLooper;
    //使用默认优先级创建给定名称的线程
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
   //使用指定的名称和优先级
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    ...........
 }
//重写此方法在Looper.loop之前做一些初始化动作
 protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        //获取当前进程id
        mTid = Process.myTid();
        //准备looper
        Looper.prepare();
        //同步机制获取当前Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
            //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
            notifyAll();
        }
        //设置线程优先级
        Process.setThreadPriority(mPriority);
        //调用初始化方法,默认为空的
        onLooperPrepared();
        //Looper开始工作
        Looper.loop();
        mTid = -1;
    }
 public Looper getLooper() {
         //当前线程未启动则返回null
        if (!isAlive()) {
            return null;
        }


        synchronized (this) {
            //线程已经启动,并且Looper还未创建,等待,直到收到Looper创建成功的通知
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

退出HandlerThread:

  public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }


    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

两种退出方式,quit是不安全的,因为这样会使Looper不再处理消息队列中剩下的消息,效率高点。
quitSafely是安全的,looper处理完消息后再退出,效率低点。

注意

Handler的创建应该放在HandlerThread调用start方法以后,因为在HandlerThread的run方法里才去创建Looper,否则会出现空指针

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值