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

android:id="@+id/start"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Start" />

```

Handler使用实例三:

在这个例子中,我们将验证仅使用Handler的post方法是否处于同一个线程。首先,在主activity的onCreate函数中打印两条关于本线程的信息。然后,创建一个Handler并为其绑定一个线程。在线程的run方法中,也打印线程的信息。观察这两个信息是否相同。

结果如下:

这表明这两个线程确实是同一线程。同时,我们还可以看到主界面中的文字大约过了5秒才显示出来。这是因为setContentView(R.layout.activity_main)语句放在了handler的post启动语句后面,而handler绑定的线程中又延时了5秒。因此,这也证明了只有在同一线程下才会出现这种情况。此外,Logcat中还打印出以下日志:

```

09-06 17:10:19.353: I/Choreographer(19937): Skipped 62 frames! The application may be doing too much work on its main thread.

```

源代码:

其它部分保持不变,程序运行时主界面内容立刻就显示出来了,系统输出如下:

```

这说明这样绑定的线程与它所在的activity线程就不是同一个线程了。

```

这个例子将演示如何不使用`runnable`来启动一个线程,而是通过`HandlerThread`的`looper`构造一个处理程序(handler),该处理程序自行获取和传递消息。在另一个线程中完成这些操作。

我们可以利用消息结构中的参数`arg1`和`arg2`传递简单的整型数据,也可以使用它的`Object`参数传递一些较小的数据对象。如果需要传输较大的数据,可以使用消息的`setData()`方法,该方法接收一个`Bundle`作为参数,其中存放了键值对的映射(map),但其键值类型和数据类型较为固定。

源代码如下:

```java

public class MainActivity extends AppCompatActivity {

private static final int UPDATE_MESSAGE = 1;

private static final String INT_KEY = "intKey";

private static final String DOUBLE_KEY = "doubleKey";

private static final String OBJECT_KEY = "objectKey";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// 创建HandlerThread

MyHandlerThread thread = new MyHandlerThread("MyHandlerThread");

thread.start();

// 在HandlerThread的线程中创建并发送Message

Message message = Message.obtain();

Bundle bundle = new Bundle();

bundle.putInt(INT_KEY, 10);

bundle.putDouble(DOUBLE_KEY, 3.14159);

bundle.putSerializable(OBJECT_KEY, new Object()); // 注意这里需要是可序列化的对象,如自定义类的实例等

message.setData(bundle);

message.what = UPDATE_MESSAGE;

thread.getLooper().sendMessage(message);

}

private class MyHandlerThread extends Thread {

private Looper mLooper;

private Handler mHandler;

public MyHandlerThread(String name) {

super(name);

}

@Override

public void run() {

mLooper = looper(); // 这里会自动调用Looper的相关方法进行初始化,包括设置消息队列等

mHandler = new MyHandler(mLooper); // 根据Looper创建Handler实例

Looper.prepare(); // 为当前线程准备一个消息循环,此处仅做演示,实际应用中可能不需要这一步,因为HandlerThread已经为我们准备好了循环器,我们可以直接通过它来获取Looper对象。

try {

Looper.loop(); // 在消息循环中等待接收消息并处理它们。实际上这里并不需要主动退出,因为我们的Handler会在适当的时候自己停止循环。通常情况下,我们需要在合适的时机调用quit(),然后让系统回收资源。但是在这里为了简化问题,我们直接让线程运行到结束。当然这并不是一个好的实践,因为我们需要确保所有的子线程都已经完全结束了它们的工作。在实际的应用中,我们应该尽量避免这种情况的发生。

HandlerThread 是 Android API 提供的一个方便、便捷的类,使用它我们可以快速地创建一个带有 Looper 的线程。Looper 可以用来创建 Handler 实例。注意:start() 仍然必须被调用。

以下是一个关于如何使用 HandlerThread 的简单示例:

在 Activity 创建时调用 initHandlerThraed() 函数:

```java

public class MainActivity extends AppCompatActivity {

private Handler mSubThreadHandler;

private HandlerThread mHandlerThread;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initHandlerThraed();

}

private void initHandlerThraed() {

mHandlerThread = new HandlerThread("MyHandlerThread");

mHandlerThread.start();

mSubThreadHandler = new AsynchTask(this).getHandler();

}

}

```

上述代码比较简单,功能也比较简单,可以在此基础上进行扩展。

多次点击按钮,打印信息如下所示:

点击按钮,向 mSubThreadHandler 发送消息,mSubThreadHandler 中接收到消息进行处理,由打印可知 mSubThreadHandler 的 handleMessage 方法运行在子线程中。

模拟耗时操作,生成随机数,然后向主线程中(mUiHandler)发送消息(Message)。

mUiHandler 的 handleMessage 方法运行在主线程,可以用来更新 Ui 界面。

Activity 销毁的时候,调用 mHandlerThread.quit(),退出 HandlerThread 的 Looper 循环。

效果图如下:

【运行方式:右键项目:Run as -》Android Application (备注:Eclipse 需要配置 Android 开发环境)】

HandlerThread的使用

在Android开发中,HandlerThread是一个非常重要的类,它可以帮助我们实现多线程处理任务。使用HandlerThread的主要目的是为了在子线程中执行耗时操作,同时将处理结果通过Handler发送回主线程进行更新UI。下面我们来详细了解一下HandlerThread的使用方法。

1. 创建HandlerThread实例

首先,我们需要创建一个HandlerThread实例,通常情况下,我们会将其命名为"mHandlerThread",并通过构造函数传入一个String参数作为线程名字。例如:

```java

private HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");

```

2. 启动HandlerThread

接下来,我们需要调用HandlerThread的start()方法来启动线程。这个方法会自动创建一个Looper实例并开启Looper循环,从消息队列中获取消息并给Handler进行处理。例如:

```java

mHandlerThread.start();

```

3. 获取Looper实例

为了与子线程中的Handler进行通信,我们需要获取与该线程绑定的Looper实例。通常情况下,我们会在子线程的run()方法中获取Looper实例,然后在主线程中通过getLooper()方法获取对应的Looper实例。例如:

```java

mLooper = mHandlerThread.getLooper();

```

4. 创建Handler

接下来,我们需要通过子线程中的Looper实例创建Handler。通常情况下,我们会将Handler对象定义为静态成员变量,以便在多个地方使用。例如:

```java

private static class MyHandler extends Handler {

public MyHandler(Looper looper) {

super(looper);

}

}

private MyHandler mSubThreadHandler = new MyHandler(mHandlerThread.getLooper());

```

5. 在子线程中发送消息给Handler

现在我们可以在子线程中使用mSubThreadHandler发送消息了。例如,我们可以在子线程的run()方法中使用Message.obtain()方法创建消息对象,并设置目标Handler:

```java

Message message = Message.obtain();

message.what = 1; // 设置消息类型和内容

mSubThreadHandler.sendMessage(message); // 将消息发送到主线程中的Handler进行处理

```

6. 在主线程中处理消息

最后,我们需要在主线程中注册Handler,并重写其handleMessage()方法来处理接收到的消息。例如:

```java

@Override

protected void onHandleMessage(Message msg) {

switch (msg.what) {

case 1: // 根据消息类型进行相应的处理逻辑

break;

}

}

```

7. 退出HandlerThread的方法

当我们不再需要使用HandlerThread时,可以通过调用quit()或quitSafely()方法来退出消息循环。其中,quit()方法会移除消息队列中的所有消息(包括延迟消息和非延迟消息),而quitSafely()方法只会移除延迟消息,确保所有非延迟消息都能被派发出去让Handler进行处理。例如:

```java

mHandlerThread.quit(); // 退出消息循环,移除所有消息队列中的消息(包括延迟消息和非延迟消息)

// 或者使用以下方式安全地退出消息循环,确保所有非延迟消息都能被派发出去:

mHandlerThread.quitSafely(); // 退出消息循环,仅移除延迟消息,确保所有非延迟消息都能被派发出去让Handler进行处理。

HandlerThread的详解与总结至此,我们已经对HandlerThread进行了详细的讲解。在本文中,我们从创建、启动、停止和消息处理等方面对HandlerThread进行了全面的介绍。希望通过本文的学习,大家能够对HandlerThread有一个更加深入的了解。当然,如果在阅读过程中有任何问题,欢迎大家指正、交流。

四、其他补充

参考文章:深入理解Handler、Looper、Messagequeue

在学习HandlerThread的过程中,我们还可以通过阅读相关资料来加深对HandlerThread的理解。例如,可以参考《Android开发艺术探索》这本书中的关于Handler、Looper和Messagequeue的内容。通过阅读这些资料,我们可以更好地理解HandlerThread的工作原理和使用方法。同时,还可以参考一些开源项目,如微信、QQ等,了解它们是如何使用HandlerThread来实现高效的消息处理的。总之,多读多看,才能真正掌握HandlerThread的精髓。