Handler是什么
Handler是Android提供的一种机制,用于更新UI并处理消息。它允许我们在主线程中执行耗时操作,同时通过它可以发送和接收消息。
原理(解析异步消息处理机制)
Handler的工作原理如下:
1. 在主线程创建Handler对象。
2. 重写handlerMessage()方法。
3. 当子线程需要进行UI操作时,它会创建一个Message对象,并通过Handler将该消息发送出去。
4. 该消息被添加到MessageQueue中,等待Handler处理。
5. 最后,Message会被分发回到handlerMessage()方法中进行处理。由于Handler是在主线程中创建的,因此handlerMessage()方法也在主线程运行。
6. 这样就可以在主线程中进行UI操作了。
举例
以下示例演示如何使用Handler修改TextView的文字内容:
```java
// 利用Handler修改子线程UI,这里简单演示修改TextView的文字。
private Handler mHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
if (msg.what == UPDATE_TEXT_VIEW) {
TextView textView = findViewById(R.id.textView);
textView.setText("这是新的内容");
}
}
};
// 在子线程中执行耗时操作,例如从网络下载数据等
new Thread(new Runnable() {
@Override
public void run() {
// ...执行耗时操作...
mHandler.sendEmptyMessage(UPDATE_TEXT_VIEW); // 发送消息给主线程的Handler进行更新UI操作
}
}).start();
```
通过上述代码,当子线程中的耗时操作完成后,我们可以通过mHandler.sendEmptyMessage(UPDATE_TEXT_VIEW)发送一条消息给主线程的Handler。然后在handleMessage方法中判断消息类型并执行相应的UI更新操作。这样就能够在主线程中更新UI。
以下是重构后的代码:
```java
public class HandlerA {
public void sendMessage() {
}
public void sendMessageDelayed(Message msg, long delayMillis) {
}
public boolean removeMessages(int what) {
}
public int getId() {
}
public Message obtainMessage() {
}
public Message obtainMessage(int what) {
}
public Message obtainMessage(int what, Object obj) {
}
public Message obtainMessage(int what, int arg1, int arg2) {
}
public Message obtainMessage(int what, long eventTime) throws InsufficientPermissionException {
}
}
```
在Android开发中,线程的创建和管理是一个重要的环节。每个线程都有一个优先级,高优先级的线程会被优先执行。此外,线程还可以被标记为守护线程。当一个线程创建了一个新的Thread对象时,新线程的优先级会初始化为创建线程的优先级,如果创建线程是守护线程,那么新线程也会被标记为守护线程。
在Android中,有三种类型的线程:Handler、Thread和HandlerThread。它们之间的区别如下:
1. Handler:Handler在Android中负责发送和处理消息。通过它,我们可以实现其他子线程与主线程之间的消息通讯。
2. Thread:Thread是Java进程中执行运算的最小单位,也是执行处理机调度的基本单位。在一个进程中,可以有多个独立的线程同时运行。
3. HandlerThread:HandlerThread是一个继承自Thread的类。在Android中,没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类。这个类对Java的Thread做了很多便利的封装。
实际上,这个问题的主要关注点在于HandlerThread类。那么,这个类到底有什么作用?所谓的便利封装又体现在哪里?
总之,Handler、Thread和HandlerThread在Android开发中扮演着不同的角色。Handler用于实现子线程与主线程之间的消息通讯,Thread是Java进程中执行运算的基本单位,而HandlerThread则是对Java Thread的一种便利封装。了解这三者之间的区别和联系,有助于我们在实际开发中更好地利用多线程技术。
HandlerThread是Android中一个方便的类,用于启动一个具有looper的新线程。通过使用这个looper,我们可以创建handler类,从而实现在其他线程中运行handler。那么Handler和Looper之间的关系是什么呢?为什么HandlerThread需要这样的处理?请参考下图:
Android提供了Handler和Looper来满足线程间的通信需求。Handler遵循先进先出(FIFO)原则,而Looper类用于管理特定线程内对象之间的消息交换(MessageExchange)。
1. Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)和对消息进行循环。
2. Handler:你可以构造Handler对象来与Looper沟通,以便将新消息推送到MessageQueue中;或者接收Looper从MessageQueue取出所发送的消息。
3. MessageQueue(消息队列):用于存放线程放入的消息。
4. Message:是线程间通讯的消息载体。两个码头之间运输货物,Message充当集装箱的功能,里面可以存放任何你想传递的消息。
从这里我们可以看出,如果一个线程要处理消息,那么它必须拥有自己的Looper,而不是根据Handler在哪里创建就可以在哪里处理消息。
下面我们来看一下HandlerThread的使用:
正如前面所说,在Android中进行线程间通信时,例如常见的更新UI操作,涉及到的是子线程和主线程之间的通信。实现这种通信的方式就是使用Handler和Looper。但是手动操作Looper并不推荐,因此谷歌封装了HandlerThread类(类似于AsyncTask类)。
下面是一个具体的实现示例:
```java
// 创建一个HandlerThread实例
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
// 启动HandlerThread
handlerThread.start();
// 获取HandlerThread的Looper对象
Looper looper = handlerThread.getLooper();
// 创建一个Handler对象,并关联到Looper对象上
Handler handler = new Handler(looper);
```
从上述代码可以看出,HandlerThread继承于Thread,因此它本质上是一个Thread。与普通Thread的主要区别在于,HandlerThread内部直接实现了Looper的实现,这是处理Handler消息机制所必需的。有了自己的looper,我们可以在自己的线程中分发和处理消息。如果不使用HandlerThread,我们需要手动调用Looper.prepare()和Looper.loop()等方法。
为了帮助读者更好地理解Android消息机制,我们可以提供一些其他分析:
1. Handler是Android消息机制的上层接口,通过它可以轻松地将一个任务切换到Handler所在的线程中执行。这个线程可以是主线程,也可以是子线程,具体取决于构造Handler时使用的Looper位于哪个线程中。
2. Handler的运行需要底层的MessageQueue和Looper的支持。当Handler创建时,会采用线程的Looper来构造消息循环系统。然而,线程默认是没有Looper的。如果需要使用Handler,就必须为线程创建Looper。
3. 在上述代码中,第一个Handler(mainHandler)在实例化时直接在onCreate()方法中new出了实例。实际上,它已经在主线程(ActivityThread)中了。当ActivityThread被创建时,就会初始化Looper。这就是主线程中默认可以直接使用Handler的原因。
4. 第二个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的工作原理:
在Android的消息机制中,Looper扮演着消息循环的角色。具体来说,它会不停地从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是一个非常常见的概念。线程中的Handler使用原理如下:每个线程只有一个Looper来管理消息队列,而Handler在使用时需要绑定到对应的Looper上。当Handler绑定到某个Looper后,它会不断地向该Looper发送消息。而线程则通过循环读取MessageQueue队列中的消息,并将这些消息发送给Handler进行处理。
在Android系统中,UI(用户界面)是运行在主线程(MainThread)中的。主线程使用MainLooper来管理消息队列,并通过循环不断读取MessageQueue队列中的消息。如果在创建Handler对象时没有指定绑定的Looper,那么默认情况下,Handler会与主线程的Looper绑定在一起。这意味着Handler发送和处理消息都是在主线程中进行的。
为了保证用户与UI之间的交互流畅,应用程序通常会将耗时的操作(如网络操作、IO读取、数据处理等)放在子线程中执行。例如,可以通过异步获取数据的方式,在获取完成后使用主线程的Handler将消息发送到主线程的MainLooper队列中,以通知主线程进行UI刷新。
为了实现这一目标,Android提供了一个名为HandlerThread的原生组件。实际上,HandlerThread是Android封装的一个Thread类。使用HandlerThread的方法如下:
1. 创建一个HandlerThread对象,这将创建一个新的线程。然后必须调用start()方法来启动这个线程。
2. 创建一个Handler对象,在构造Handler对象时,将新创建的线程的Looper作为参数传递给构造函数。这样创建的Handler对象就与新创建的线程的Looper绑定在一起了。
3. 此时创建的Handler对象就可以向新创建的线程的MessageQueue队列发送消息和处理消息了。由于处理消息是在子线程中进行的,因此可以执行耗时的操作,而不会阻塞UI线程。一旦子线程完成耗时操作并获取到数据,就可以通过主线程的Handler将消息发送给主线程,以便更新当前的UI界面。
您好,根据提供的内容重构后的文本如下:
===========================================================================
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.方便我们创建一个拥有looper的线程。
HandlerThread继承自Thread,因此HandlerThread其实就是一个线程。线程开启时也就是run方法运行起来后,线程同时创建一个含有消息队列的looper,并对外提供自己这个对象的get方法,这就是和普通的Thread不一样的地方。可用于多个耗时任务要串行执行。如果对handler不熟的话,可以先看这个Handler介绍。使用流程:实例对象,参数为线程名字;启动线程;实例主线程的Handler,参数为HandlerThread内部的一个looper。
看个简单的例子:里面打了挺多的注释,Log日志也用序号标明了顺序。这里模拟的情况是我们在子线程下载东西,然后和主线程之间进行通信。主线程知道了下载开始和下载结束的时间,也就能及时改变界面UI。首先是DownloadThread类,继承于HandlerThread,用于下载。然后是MainActivity部分。运行的Log日志如下:例子:使用相对比较简单,总结如下:1. 创建HandlerThread对象,可以重写onLooperPrepared()方法做一些初始化操作;2. 调用handlerThread.start()方法;3. 创建Handler,在构造中传入handlerThread.getLooper()方法创建的Looper对象,重写handleMessage(Message msg)方法,在子线程处理消息;4. 使用Handler对象在相关场景发送处理消息;5. 适时退出异步操作。原理:您可以通过搜索引擎查询更多关于HandlerThread的信息。
HandlerThread的源码相对较少,以下是其主要功能的简要说明:
HandlerThread的主要作用是在子线程中封装Looper对象,使得在创建的Handler中能够进行异步的消息处理。当有耗时操作时,可以考虑使用HandlerThread机制来避免多线程并发带来的问题。
在使用HandlerThread时,需要先调用start方法来准备子线程所需的Looper对象,然后再创建Handler对象。创建Handler对象时,可以在构造方法中调用new Handler(handlerThread.getLooper())来使用Looper对象。注意创建的先后顺序。
参考文章:
1. Android中Looper的quit方法和quitSafely方法
2. Android Handler总结2-子线程中的Handler和HandlerThread的使用
3. 为子线程创建Handler
示例代码:
```java
// 创建一个子线程的Handler
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start(); // 启动子线程
Handler handler = new Handler(handlerThread.getLooper()); // 在子线程中创建Handler,并指定Looper
```
通过使用HandlerThread,可以避免在UI线程中直接创建子线程的Handler时可能出现的多线程并发问题。
==================
在HandlerThread中,如果Looper对象没有创建成功,当前线程将一直处于等待状态。因此,我们需要确保在HandlerThread的run方法中成功创建Looper对象以唤醒所有等待的线程。以下是HandlerThread的唤醒源代码:
```java
public class MyHandlerThread extends HandlerThread {
public MyHandlerThread(String name) {
super(name);
}
@Override
protected void onLooperPrepared() {
myLooper = getLooper();
for (Handler handler : handlers) {
handler.sendMessage(handler.obtainMessage());
}
}
private Looper myLooper;
public synchronized void addHandler(Handler handler) {
if (myLooper != null) {
handler.sendMessage(handler.obtainMessage());
} else {
handlers.add(handler);
}
}
}
```
Android Handler有四个使用实例及HandlerThread的使用:
1. 在应用程序启动时,主线程(UI线程)负责管理界面中的UI控件和事件分发。当需要进行耗时操作时,例如联网读取数据或读取较大的本地文件,应将这些操作放在一个子线程中执行,因为子线程涉及到UI更新,而Android主线程是线程不安全的。此时,可以使用Handler来解决这个问题。通过将Handler绑定到它所建立的线程中,可以实现在子线程中向主线程发送消息并更新UI。
2. 在主线程中post Runnable对象,运行run接口。这个例子介绍了最简单的Handler使用方式。单击“开始”按钮后,程序会启动线程并在完成后延时1秒继续启动该线程。每次线程的run函数中都会输出"UpdateThread..."文字,并重复执行。当单击“结束”按钮时,该线程将停止。如果再次单击“开始”,则文字将再次输出。
Handler使用实例二:
在这个例子中,我们将使用Handler的sendMessage方法来处理消息。当用户点击“Start”按钮时,会启动一个线程并将其绑定到Handler中。然后,通过sendMessage方法向消息队列中发送带有参数的消息。在Handler中,我们使用handleMessage方法来处理这些消息。处理方法是获取消息队列中的消息参数,并使用这些参数来完成其他功能。在这个例子中,我们将使用这些参数来更新进度条。
源代码:
布局文件:
```xml