Android HandlerThread案例详解

HandlerThread 顾名思义就是一种可以使用 Handler 的 Thread。日常开发中我们经常会通过创建一个 Thread 去执行任务,有多个任务就多创建几个线程实现,这时候可能出现线程同步的问题。不过有时候我们并不需要很强的并发性,只需保证按照顺序地执行各个任务即可,有什么好办法实现呢?第一反应想到的可能是通过 Executors.newSingleThreadExecutor() 方法来创建一个 SingleThreadExecutor,来统一所有的任务到一个线程中,然后按顺序执行。其实,除了这个方法之外,HandlerThread 也可以实现。

简单使用

首先创建一个 HandlerThreadActivity

public class HandlerThreadActivity extends BaseActivity {

    private static final String TAG = "HandlerThreadActivity";

    private Button mStartBtn;
    private Handler mHandler;
    private HandlerThread mHandlerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread);
        mStartBtn = findViewById(R.id.start_btn);

        mHandlerThread = new HandlerThread("THREAD_NAME");
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());

        mStartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, Thread.currentThread().getId() + " " + String.valueOf((Looper.myLooper() == Looper.getMainLooper())) + " 任务:" + this.hashCode());
                        SystemClock.sleep(3000);
                    }
                });
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }
}

快速三击按钮,打印日志如下:

可以发现,三次不同的任务按开始的顺序执行,而且是运行在子线程中,那到底是怎么实现的呢?

源码解析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

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

    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        // 获取线程 id
        mTid = Process.myTid();
        //构建一个 Looper
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        //设置线程优先级
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        // Looper 循环
        mTid = -1;
    }

     // 获取当前线程的 Looper,
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

     /**
     * @return a shared {@link Handler} associated with this thread
     * @hide 方法隐藏掉,无法调用
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

     //线程退出方法,主要是调用 Looper.quit() 方法,不然一直在循环
    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;
    }

    public int getThreadId() {
        return mTid;
    }
}

通读下来,如果熟悉 Handler 原理的同学大概就明白 HandlerThread 的机制了:

  • HandlerThread 运行 start() 方法,回调 run() 方法。
  • 在 run() 方法中通过 Looper.prepare() 来创建消息队列,并通过 Looper.looper() 方法来开启消息循环。
  • 由于 Loop.loop() 是一个死循环,导致 run() 也是无线循环,因此当我们不需要使用 HandlerThread 的时候,要调用它的 quit() 方法或者 quiteSafely() 方法。

到此这篇关于Android HandlerThread案例详解的文章就介绍到这了,更多相关Android HandlerThread内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 多线程Thread,Runnable,Callable实现方式

    目录 一.创建线程的常用三种方式 1.继承Thread类 2.实现Runnable接口(重点) 以多个线程并发,解决方法为例 3. 实现Callable接口(JDK1.5版本之后引入的) 总结 一.创建线程的常用三种方式 1.继承Thread类 创建MyThread 类并继承Thread package com.zrrd.XianCheng; /** *继承Thread类,达到线程的能力 */ public class MyThread extends Thread{ private Strin

  • 一篇文章带你了解Java中ThreadPool线程池

    目录 ThreadPool 线程池的优势 线程池的特点 1 线程池的方法 (1) newFixedThreadPool (2) newSingleThreadExecutor (3) newScheduledThreadPool (4) newCachedThreadPool 2 线程池底层原理 3 线程池策略及分析 拒绝策略 如何设置maximumPoolSize大小 ThreadPool 线程池的优势 线程池做的工作主要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些

  • Java并发教程之Callable和Future接口详解

    刚把Thread 的知识理了一遍. Runnable是一个接口,而Thread是Runnable的一个实现类. 所以也就有了之前创建线程的两种方法 继承Thread 实现Runnable 我们看一下新建线程的方法: 都是得传入一个Runnable对象(这句话很关键) 所以传入一个Runnble和Thread对象都行. 现在引入创建线程的第三种方法:Callable 为了实现 Runnable,需要实现不返回任何内容的 run()方法,而对于 Callable,需要实现在完成时返回结果的 call

  • 多线程_解决Runnable接口无start()方法的情况

    为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢? 实现Runnable接口,避免了继承Thread类的单继承局限性.覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中. 创建Thread类的对象,只有创建Thread类的对象才可以创建线程.线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建

  • Java Thread之Sleep()案例详解

    一.API简介 Thread.sleep()是Thread类的一个静态方法,使当前线程休眠,进入阻塞状态(暂停执行),如果线程在睡眠状态被中断,将会抛出IterruptedException中断异常..主要方法如下: [a]sleep(long millis)  线程睡眠 millis 毫秒 [b]sleep(long millis, int nanos)  线程睡眠 millis 毫秒 + nanos 纳秒 Api文档: 二.使用方法 注意:在哪个线程里面调用sleep()方法就阻塞哪个线程.

  • Android HandlerThread案例详解

    HandlerThread 顾名思义就是一种可以使用 Handler 的 Thread.日常开发中我们经常会通过创建一个 Thread 去执行任务,有多个任务就多创建几个线程实现,这时候可能出现线程同步的问题.不过有时候我们并不需要很强的并发性,只需保证按照顺序地执行各个任务即可,有什么好办法实现呢?第一反应想到的可能是通过 Executors.newSingleThreadExecutor() 方法来创建一个 SingleThreadExecutor,来统一所有的任务到一个线程中,然后按顺序执

  • Android handle-message的发送与处理案例详解

    1.Handle,MessageQueue,Message类图 Handle: 处理消息,并提供一系列函数帮忙我们创建消息和插入消息到消息队列中 创建handle实例--PbapClientConnectionHandler mHandlerThread = new HandlerThread("PBAP PCE handler", Process.THREAD_PRIORITY_BACKGROUND); mHandlerThread.start(); //将这个线程设置为消息处理Lo

  • Android开发之对话框案例详解(五种对话框)

    下面通过实例代码给大家分享5种android对话框,具体内容详情如下所示: 1 弹出普通对话框 --- 系统更新 2 自定义对话框-- 用户登录 3 时间选择对话框 -- 时间对话框 4 进度条对话框 -- 信息加载.. 5 popuWindow对话框 1 弹出普通对话框 --- 系统更新  //弹出普通对话框 public void showNormalDialog(View v) { AlertDialog.Builder builder = new Builder(this); //设置D

  • Android notifyDataSetChanged() 动态更新ListView案例详解

    有时候我们需要修改已经生成的列表,添加或者修改数据,notifyDataSetChanged()可以在修改适配器绑定的数组后,不用重新刷新Activity,通知Activity更新ListView.今天的例子就是通过Handler AsyncTask两种方式来动态更新ListView. <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://sc

  • Android ExpandableListView使用方法案例详解

    目录 一.前言 二.实现的功能 三.具体代码 1.主xml代码 2.父布局xml代码 3.子布局xml代码 4.主activity代码 5.adapter代码 一.前言   "好记性不如烂笔头",再次验证了这句话是真的很有道理啊,一个月前看了一下ExpandableListView的使用,今天再看居然忘了这个是干啥的了,今天就详细讲解一下ExpandableListView的使用方法,感觉对于二级条目显示功能都可以实现. 二.实现的功能 1.可实现二级列表条目显示功能,具体包括可自定义

  • Android Intent与IntentFilter案例详解

    1. 前言        在Android中有四大组件,这些组件中有三个组件与Intent相关,可见Intent在Android整个生态中的地位高度.Intent是信息的载体,用它可以去请求组件做相应的操作,但是相对于这个功能,Intent本身的结构更值得我们去研究. 2. Intent与组件        Intent促进了组件之间的交互,这对于开发者非常重要,而且它还能做为消息的载体,去指导组件做出相应的行为,也就是说Intent可以携带数据,传递给Activity/Service/Broa

  • Android LayoutParams使用案例详解

    LayoutParams是什么? LayoutParams主要保存了一个View的布局参数,因此可以使用LayoutParams来改变布局参数从而达到View位置的效果,一般在自定义View的时候使用. LayoutParams怎么用? 如果父控件是LinearLayout,需要使用LinearLayout.LayoutParams 代码如下: LinearLayout.LayoutParams layoutParams=(LinearLayout.LayoutParams)getLayoutP

  • Android 使用registerReceiver注册BroadcastReceiver案例详解

    android.context.ContextWrapper.registerReceiver public Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter) Register a BroadcastReceiver to be run in the main activity thread. The receiver will be called with any broadcast Intent

  • Android 启动模式FLAG_ACTIVITY_CLEAR_TOP案例详解

    四种启动模式 standard: 只要被启动就会创建一个新的 singleTop: 栈顶复用(当被启动的Activity处于Task栈顶时,可以复用,直接调用onNewIntent方法) singleTask: 栈中复用(被启动的Activity已经处于栈中,会将上边的Activity清除出栈,调用onNewIntent) singleInstance 全局单实例(应用场景:地图,Activity初始化需要大量资源) Intent的标志位FLAG Intent.FLAG_ACTIVITY_SIN

  • Android AlertDialog六种创建方式案例详解

    目录 一.setMessage:设置对话框内容为简单文本内容 二.setItem:设置文本框内容为简单列表项 三.setSingleChoiceItems()设置对话框内容为单选列表项 四.setMultiChoiceItems()设置对话框内容为多选项列表 五.setAdapter()设置对话框内容为自定义列表项(这里是一个布局) 六.setView()设置对话框为自定义View 创建AlertDialog的步骤: 创建AlertDialog.Builder对象 调用Builder对象的set

随机推荐