Android多线程-HandlerThread用法与源码解析

使用HandlerThread好处

在Android开发中,我们经常使用多线程编程。而多线程有多种方式实现。其中我们用得最多、也是最早接触的是使直接开一个线程Thread

new Thread(){
    @Override
    public void run() {
        //do something here
    }
}.start();

先抛开这样开线程的弊端,因为在有时做一些简单的任务时,这样写确实能减少代码量;我们先说说线程间通讯。Android自带提供HandlerLooper的组合来实现。使用方法相信大家都很熟悉了。而HandlerThread就是为了实现多线程之间通讯的一个类,可以减少一定的代码量。

HandlerThread源码解析

首先,我们先看看源码(不感兴趣可以跳过,下方有使用方法解析):

package android.os;

/**
 * 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.
 * 
 * 这是一个方便启动一个带有`Looper`的`Thread`,然而`start()`还是需要被调用
 *
 */
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     *
     * 输入的优先级是来自`android.os.Process`里的,而不是来自`java.lang.Thread`里的
     *
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

这是HandlerThread类的开头,我们可以看到,这个类属于android.os包,属于sdk内的类,使用方便,无需另外导入。
该类继承于Thread类,本质上是一个线程。
该类提供两个构造方法,单参数构造方法,输入参数为线程名字,双参数构造方法输入线程名字以及线程优先级,这里需要注意一点,输入的优先级是android.os.Process里的,而不是java.lang.Thread里的。

我们再往下看代码:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

这是核心部分,当线程被启动后,调用该run()方法。首先,记录了该线程的id号,然后调用Looper.prepare(),创建该线程上的looper对象。
接着对自身对象加锁,并获取该线程上的looper引用,并调用notifyAll(),唤醒其他正在等待该对象的线程。做这一步的原因,我们后面再做解释。
然后在进程里对当前线程设置优先级。
最后调用Looper.loop(),启动looper的消息队列循环。
到此,该类以及基本可以运行了

我们再往下看代码:

/**
 * This method returns the Looper associated with this thread. If this thread not been started
 * or for any reason is isAlive() returns false, this method will return null. If this thread 
 * has been started, this method will block until the looper has been initialized. 
 * 
 * 该方法会返回一个关联该线程的Looper
 * 如果该线程还未启动,或者某种原因isAlive返回false,这个方法会会返回null值
 * 如果线程已经启动,这个方法会阻塞,直到looper被初始化
 * 
 * @return The looper.
 */
public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }

//If the thread has been started, wait until the looper has been created.
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

从注释中,我们可以看到,该方法是返回一个和该类线程相关的looper,首先判断该线程是否正在运行,若否,则返回一个空值(线程未启动,当然没有关联的looper)。
接着对自身对象加锁,再次判断线程是否正在运行,且mLooper是否已经赋值。这里用到的方法是双重检测,和单例模式中的双重检测是一样的。若线程已经在运行,但mLooper未赋值,那就在该线程等待。
我们可以和上面的run方法联系起来了。直到run()方法执行到notifyALL(),才被唤醒,继续判断,直到mLooper赋值,返回mLooper
这样写的目的是为了防止多线程操作下,防止某个线程从一个已经运行的HandlerThread但还未完成run方法的对象里,获取到空的looper引用。

HandlerThread用法

那么我们平时怎么使用HandlerThread这个类呢?
首先我们可以创建一个HandlerThread类实例,并运行该线程,那么该线程就开始进入等待消息的状态:

handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();

接着我们可以创建一个和该线程的Handler,里面实现我们业务需求的执行的方法,构造方法里就可以传入我们HandlerThread类实例的looper,这样,handler就和我们的线程关联在一起了:

handler =new Handler(handlerThread.getLooper()){
    @Override
    public void handleMessage(Message msg) {
        //这里可以实现我们的业务需求
        Log.i(TAG,"receive msg:"+msg.what);
    }
};

接下来,就和我们平时使用handler一样使用了,该任务就会在HandlerThread实例的线程运行了:

handler.sendEmptyMessage(123);
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值