一、前期知识储备

(1)Handler类,上官方文档,Handler

public class Handler.A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

(2)Thread类,上官方文档,Thread

public class Thread. extends Object implements Runnable.A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.

Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.

(3)HandlerThread类,上官方文档,HandlerThread

public class HandlerThread. extends Thread. 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.

二、三者的区别

①Handler:在android中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯。

②Thread:Java进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。

③HandlerThread:一个继承自Thread的类HandlerThread,Android中没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类,这个类对Java的Thread做了很多便利的封装。

———————————————————我是分割线—————————————————————

其实这个问题,最主要的关注点还是落在了HandlerThread类上,那么这个类到底有什么作用,所谓的便利封装又体现在哪里?

观察HandlerThread的官方文档的两句:①Thread. Handy class for starting a new thread that has a looper.②The looper can then be used to create handler classes.

释义:HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler,之后Handler就可以运行在其他线程中了

———————————————————我是分割线—————————————————————

那么Handler和Looper到底是什么关系,为什么HandlerThread要做这样的处理?观看下图:

                      

Andriod提供了 Handler  和  Looper  来满足线程间的通信。 Handler 先进先出原则。 Looper 类用来管理特定线程内对象之间的消息交换 (MessageExchange) 。 

1)Looper:  一个线程可以产生一个 Looper 对象,由它来管理此线程里的 MessageQueue( 消息队列 ) 和对消息进行循环。 

2)Handler:  你可以构造 Handler 对象来与 Looper 沟通,以便 push 新消息到 MessageQueue 里 ; 或者接收 Looper 从 Message Queue 取出 所送来的消息。 

3) Message Queue( 消息队列 ): 用来存放线程放入的消息。 

4) Message:是线程间通讯的消息载体。两个码头之间运输货物,Message充当集装箱的功能,里面可以存放任何你想传递的消息。

看到这里就明白了为什么:如果一个线程要处理消息,那么它必须拥有自己的Looper,并不是Handler在哪里创建,就可以在哪里处理消息。

注:对应关系Thread(1):Looper(1):MessageQueen(1):Handler(n).

三、HandlerThread的使用

正如前面所说,线程间通信的时候,比如Android中常见的更新UI,涉及到的是子线程和主线程之间的通信,实现方式就是Handler Looper,但是要自己手动操作Looper,不推荐,所以谷歌封装了HandlerThread类(类似于AsyncTask类)。

上代码,具体实现:

public class MainActivity extends AppCompatActivity {
 
    Handler mainHandler,workHandler;
    HandlerThread mHandlerThread;
    TextView text;
    Button button1,button2;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = (TextView) findViewById(R.id.text1);
 
        // 创建与主线程关联的Handler
        mainHandler = new Handler();
        /**
          * 步骤①:创建HandlerThread实例对象
          * 传入参数 = 线程名字,作用 = 标记该线程
          */
        mHandlerThread = new HandlerThread("handlerThread");
 
        /**
         * 步骤②:启动线程
         */
        mHandlerThread.start();
 
        /**
         * 步骤③:创建工作线程Handler & 复写handleMessage()
         * 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
         * 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
         */
 
        workHandler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg)
            {
                //设置了两种消息处理操作,通过msg来进行识别
                switch(msg.what){
                    case 1:
                        try {
                            //延时操作
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // 通过主线程Handler.post方法进行在主线程的UI更新操作
                        mainHandler.post(new Runnable() {
                            @Override
                            public void run () {
                                text.setText("第一次执行");
                            }
                        });
                        break;
                    case 2:
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        mainHandler.post(new Runnable() {
                            @Override
                            public void run () {
                                text.setText("第二次执行");
                            }
                        });
                        break;
                    default:
                        break;
                }
            }
        };
 
        /**
         * 步骤④:使用工作线程Handler向工作线程的消息队列发送消息
         * 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
         */
        button1 = (Button) findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = Message.obtain();
                msg.what = 1; //消息的标识
                msg.obj = "A"; // 消息的存放
                // 通过Handler发送消息到其绑定的消息队列
                workHandler.sendMessage(msg);
            }
        });
 
        button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = Message.obtain();
                msg.what = 2; 
                msg.obj = "B"; 
                workHandler.sendMessage(msg);
            }
        });
 
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit(); // 退出消息循环
        workHandler.removeCallbacks(null); // 防止Handler内存泄露 清空消息队列
    }
}

从上面代码可以看出,HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,然后在内部直接实现了Looper的实现,这是Handler消息机制必不可少的。有了自己的looper,可以让我们在自己的线程中分发和处理消息。如果不用HandlerThread的话,需要手动去调用Looper.prepare()Looper.loop()这些方法。

// 子线程中创建新的Handler 没有使用HandlerThread
new Thread () {
    @Override
    public void run() {
        Looper.prepare();
        Hnadler handler = new Handler();
        Looper.loop();
    } 
}

提供一些其他Android消息机制分析,帮助理解读者理解:

①Handler是Android消息机制的上层接口,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行,该线程既可以是主线程,也可以是子线程,要看构造Handler时使用的构造方法中传入的Looper位于哪里;

②Handler的运行需要底层的MessageQueue和Looper的支撑,Handler创建的时候会采用当前线程的Looper来构造消息循环系统,而线程默认是没有Looper的,如果需要使用Handler就必须为线程创建Looper;

③上述代码中的第一个Handler-mainHandler,实例化的时候,直接在onCreate()方法中new出了实例,其实是其已经在主线程中了,主线程-ActivityThread,ActivityThread被创建时就会初始化Looper,这就是主线程中默认可以直接使用Handler的原因;

④上述代码中的第二个Handler-workHandler,它在实例化的时候,参数传入了 mHandlerThread.getLooper() ,注意,这个Handler使用的就不是主线程的Looper了,而是子线程的Looper,HandlerThread在调用start()方法之后,就可以获取到子线程的Looper,然后将其传入workHandler的构造方法中,那么此时的workHandler就会运行在子线程中,用于处理耗时操作。

⑤Handler的工作原理:Handler创建时会采用当前线程的Looper来构建内部消息循环系统,如果当前线程没有Looper,那么就会报错“Can`t create handler inside thread that has not called Looper.prepare()”解决方法有两个:为当前线程创建Looper即可,像上述代码中workHandler,或者在一个有Looper的线程中创建Handler也行,就像上述代码中的mainHandler一样;

⑥调用Handler的post方法会将一个Runnable投递到Handler内部的Looper中去处理,也可以通过Handler的send方法来发送一个消息,这个消息同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的。每当Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable的run方法或者Handler的handleMessage方法就会被调用。注意Looper是运行在创建Handler所在的线程中的,这样一来Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了;

⑦Looper的工作原理:Looper在Android的消息机制中扮演着消息循环的角色,具体来说就是它会不停地从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。注意关注一些重要的Looper的方法:

  • Looper.prepare()-为当前线程创建一个Looper;
  • Looper.loop()-开启消息循环,只有调用该方法,消息循环系统才会开始循环;
  • Looper.prepareMainLooper()-为主线程也就是ActivityThread创建Looper使用;
  • Looper.getMainLooper()-通过该方法可以在任意地方获取到主线程的Looper;
  • Looper.quit() Looper.quitSafely()-退出Looper,自主创建的Looper建议在不使用的时候退出

⑧ActivityThread主线程通过ApplicationThread和AMS进行进程间通信

到此这篇关于Android中Handler、Thread、HandlerThread三者的区别的文章就介绍到这了,更多相关Android中Handler、Thread、HandlerThread三者的区别内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Android中Handler、Thread、HandlerThread三者的区别的更多相关文章

  1. ios – 来自UIAlertController的self.navigationController?.popViewControllerAnimated

    我是新手,但我想我已经掌握了它.这让我的进步很难过.我想要做的是当我们无法找到他的查询的相关数据时向用户抛出错误消息,然后继续将他带回到之前的ViewController.但是,我在这方面遇到了麻烦.在我添加操作的行上,我收到以下错误:’UIViewController?’不是Void的子类型我该怎么做呢?

  2. ios – Swift闭包为AnyObject

    如何将()–>()转换为AnyObject?我试图将它转换为:处理程序为AnyObject,但它给我一个错误说:()–>()不符合协议’AnyObject’解决方法HowcanIcast()->()intoAnyObject?

  3. Twilio电话在iOS和Android中无法正常工作

    我正在尝试使用twilioclient在反应本机应用程序.这里是链接Twiliorepo完成所有设置与反应本机twilio.当我打电话一个数字得到问题.我使用了这个链接中的所有步骤.[tid:com.facebook.react.JavaScript]处理程序不是一个函数.(在“处理程序(rtn)”中,’handler’是未定义的)2016-09-2711:00:57.857[致命][tid:co

  4. iOS Parse Stripe Integration

    所有指南和文档都指向了这个方向.我真的不明白GET/POST是什么以及它如何适合iOSObjective-C编程.关于如何设置它的任何指导都将非常感激.我已经坚持了一段时间了.解决方法Parse的条带API并不像它应该的那样完整.它本身不包含许多功能,但可以通过HTTP请求完成.我必须学习一点Javascript和HTTP请求以获得许多功能.当然,你的第一直觉应该告诉你不要在任何设备上存储CC号码!

  5. [Swift]UIKit学习之警告框:UIAlertController和UIAlertView

    Important:UIAlertViewisdeprecatediniOS8.(NotethatUIAlertViewDelegateisalsodeprecated.)TocreateandmanagealertsiniOS8andlater,insteaduseUIAlertControllerwithapreferredStyleofUIAlertControllerStyleAlert.

  6. Swift基础之对话框UIAlertController

    varalertController=UIAlertController(title:"标题",message:"这是一个UIAlertController的默认样式",preferredStyle:UIAlertControllerStyle.Alert)varcancelAction=UIAlertAction(title:"取消",style:UIAlertActionStyle.Cance

  7. Swift下弹出对话框

  8. UIAlertController 测试的修正

    作者:dom,原文链接,原文日期:2015-11-25译者:小袋子;校对:lfb_CD;定稿:千叶知风两个月前,我曾发布了一篇如何测试UIAlertController的文章。一个读者发现测试没有如期地起作用:@dasdom你的测试是正常的,但是在MockUIAction中的简便init方法没有被调用。那是因为handler确实被调用了,看起来就像UIAlertAction真的把handler作为内部变量去存储动作的handler闭包。这是非常脆弱的,并且Larhythimx在另一个tweet指出在他的测

  9. Swift2.0-异常处理Exception handler

    Swift2.0-异常处理前言关于我们为什么要使用异常处理,请看百度百科为我们作出的描述,想要更详细的资料请点这里以上摘自百度百科:关联,在Objective-C中,异常处理一般都是使用NSError类接收异常和抛出异常,使用方法像这样不得不说,Swift的异常处理更为优雅,下面会重点介绍。去执行该函数不建议使用try!

  10. Swift面向协议编程简介

    Swift面向协议编程简介协议是Swift编程语言中一个非常强大的特性。Swift在编译时检查协议一致性问题,使得开发者可以在运行程序前发现代码中的一些致命错误。Swfit通过提供一些最常见奇怪问题的解决方案以及许多其他编程语言的接口限制,进一步获得了使用协议的便利性。Swift标准库扩展除了扩展自己的协议,还可以扩展来自Swift标准库的协议。

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

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

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部