HandlerThread 之于Thread区别以及使用规则

2023-10-24 23:09

本文主要是介绍HandlerThread 之于Thread区别以及使用规则,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它有个Looper成员变量。这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是 消息队列+消息循环。

当我们需要一个工作者线程,而不是把它当作一次性消耗品,用过即废弃的话,就可以使用它。

    private Handler mHandler = null;

    private HandlerThread mHandlerThread = null;

    private void sentRunnableToWorker(Runnable run){

        if (null == mHandlerThread)
        {
            mHandlerThread = new HandlerThread("WorkerThread");

            // 给工作者线程低优先级 
            mHandlerThread.setPriority(Thread.MIN_PRIORITY);
            mHandlerThread.start();
        }

        if (null == mHandler)
            mHandler = new Handler(mHandlerThread.getLooper());

        mHandler.post(run);

    }

AsyncQueryHandler就是基于HandlerThread封装了线程间双向通信,而HandlerThread只做了一半。

 

 

源码分析:

 

  1. public class HandlerThread extends Thread{
  2.           //线程的优先级
  3.            private int mPriority;
  4.           //线程的id
  5.            private int mTid=-1;
  6.            private Looper mLooper;
  7.            public HandlerThread(String name){
  8.                       super(name);
  9.                      //设置优先级为默认线程
  10.                      mPriority=Process.THREAD_PRIORITY_DEFAULT;
  11.            }
  12.            public HandlerThread(String name,int priority){
  13.                       super(name);
  14.                      mPriority=priority;
  15.            }
  16.           //这个如果有需要的话可以继承重写,例如可以在里面声明个Handler 关联此线程。
  17.            protected void onLooperPrepared(){}
  18.            //这个很熟悉吧
  19.            public void run(){
  20.                //得到当前线程的id
  21.                 mTid=Process.myTid;
  22.                //一旦调用这句代码,就在此线程中创建了Looper 对象。这就是为什么我们要在调用线程的start()方法后
  23.                //才能得到Looper 对象即 当 调用Looper.myLooper()时不为Null。
  24.                 Looper.prepare();
  25.                 //同步代码块,意思就是当获得mLooper对象后,唤醒所有线程。(会在以后的例子中有所体现)
  26.                synchronized(this){
  27.                      mLooper=Looper.myLooper();
  28.                      notifyAll();
  29.                }
  30.               //设置线程的优先级
  31.                Process.setThreadPriority(mPriority);
  32.              //调用上面的方法(需要用户重写)
  33.               onLooperPrepared();
  34.                //建立了消息循环
  35.                 Looper.loop();
  36.                mTid=-1;
  37.            }
  38.            public Looper getLooper(){
  39.                     //线程死了,那就只有NULL了。
  40.                      if(!isAlive()){
  41.                         return null;
  42.                     }
  43.             //看见没,又是同步代码块,正好和上面的形成对应,就是说只要线程活着并且我的looper为NULL,那么我就让你一直等。。。
  44.                    synchronized(this){
  45.                           while(isAlive()&&mLooper==null){
  46.                                try{
  47.                                          wait();
  48.                                    }catch(InterruptedException e){}
  49.                           }
  50.                    }
  51.                              return mLooper;
  52.            }
  53.           public boolean quit(){
  54.               Looper looper =getLooper();
  55.                if(looper!=null){
  56.                   //退出消息循环
  57.                    looper.quit();
  58.                    return true;
  59.               }
  60.               return false;
  61.        }
  62.          //返回线程ID
  63.          public int getThreadId(){
  64.                return mTid;
  65.         }
  66. }
复制代码

整体来说代码还是比较浅显易懂的。主要的作用是建立了一个线程,并且创立了消息队列,有来自己的looper,可以让我们在自己的线程中分发和处理消息。具体的使用示例,我会在下一帖中体现。还有要说明的是handler 与谁相关联不是看声明在什么地方,是看与哪个线程的looper挂钩。默认是主线程的looper.因为主线程中默认就有了looper,消息循环队列。

每天进步一点点之AsyncQueryHandler学习

AsyncQueryHandler:异步的查询操作帮助类,其实它同样可以处理增删改

1。AsyncQueryHandler的作用

查询其API便可知,它担供:

startInsert

startDelete

startUpdate

startQuery

这四个操作,并提供相对应的onXXXComplete方法,以供操作完数据库后进行其它的操作,这四个onXXXComplete方法都是空实现,以便我们只需要去实现我们关注的操作。

 

2。为什么要使用AsyncQueryHandler

当然你也可以使用ContentProvider去操作数据库。

这在数据量很小的时候是没有问题的,但是如果数据量大了,可能导致UI线程发生ANR事件。

当然你也可以写个Handler去做这些操作,只是你每次使用ContentProvider时都要再写个Handler,必然降低了效率。

因此API提供了一个操作数据库的通用方法。

 

3。如何使用AsyncQueryHandler

你只需要继承AsyncQueryHandler类,并提供onXXXComplete方法的实现(可以实现任何一个或多个,当然你也可以一个也不实现,如果你不关注操作数据库的結果),在你的实现中做一些对数据库操作完成的处理。

使用时直接调用startXXX方法即可。传入的通用参数如下:

int token,一个令牌,需要跟onXXXComplete方法传入的一致。(当然你也可以不一致,同样在数据库的操作结束后会调用对应的onXXXComplete方法 )

Object cookie,你想传给onXXXComplete方法使用的一个对象。(没有的话传递null即可。基本发现这个变量没太大作用)

Uri uri,(不解释)

 

4。AsyncQueryHandler还为我们做了什么

AsyncQueryHandler中使用了一个WeakReference<ContentResolver>对象,即ContentResolver的弱引用  作用:当contentProvied发生变化时候同步更新仍可以通过使用AsyncQueryHandler类来达到这一要求(暂时还没理解这个作用)

同时,在它执行操作数据库时,吃掉了所有的异常。见如下代码。

 catch (Exception e) {
                        Log.w(TAG, e.toString());
                        cursor = null;
 }

这篇关于HandlerThread 之于Thread区别以及使用规则的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/278377

相关文章

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

SQL Server使用SELECT INTO实现表备份的代码示例

《SQLServer使用SELECTINTO实现表备份的代码示例》在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误,在SQLServer中,可以使用SELECTINT... 在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SE

使用Python合并 Excel单元格指定行列或单元格范围

《使用Python合并Excel单元格指定行列或单元格范围》合并Excel单元格是Excel数据处理和表格设计中的一项常用操作,本文将介绍如何通过Python合并Excel中的指定行列或单... 目录python Excel库安装Python合并Excel 中的指定行Python合并Excel 中的指定列P

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

golang1.23版本之前 Timer Reset方法无法正确使用

《golang1.23版本之前TimerReset方法无法正确使用》在Go1.23之前,使用`time.Reset`函数时需要先调用`Stop`并明确从timer的channel中抽取出东西,以避... 目录golang1.23 之前 Reset ​到底有什么问题golang1.23 之前到底应该如何正确的

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Linux alias的三种使用场景方式

《Linuxalias的三种使用场景方式》文章介绍了Linux中`alias`命令的三种使用场景:临时别名、用户级别别名和系统级别别名,临时别名仅在当前终端有效,用户级别别名在当前用户下所有终端有效... 目录linux alias三种使用场景一次性适用于当前用户全局生效,所有用户都可调用删除总结Linux