Android:什么时候应该使用Handler()?什么时候应该使用线程?


129

当我需要异步运行的东西(例如长时间运行的任务或使用网络的逻辑),或出于任何原因,启动新线程并运行它可以正常工作。创建一个处理程序并运行它也可以正常工作。有什么不同?我什么时候应该使用每个?使用a Handler和不使用a的优点/原因是Thread什么?

PS。-为了这个问题,让我们忽略AsyncTask。- Handler().postDelayed用例对我来说很清楚,为这个问题,让我们假设我需要立即启动任务。


在您的情况下,直接使用新线程,我的下一个建议是AsyncTask,但这不是您想要的。如果要向可运行对象添加延迟或某些其他类型的自定义,则通常使用处理程序。
kabuto178

1
@ kabuto178好吧,这些处理程序还有其他好处值得一提,您跳过了。比如,能够从一个单独的线程UI线程交互..
tony9099

Answers:


168

如果您正在做的事情“繁重”,则应在线程中进行。如果您未在其自己的线程中显式启动它,则它将在主(UI)线程上运行,这可能会引起用户紧张不安或响应界面缓慢。

有趣的是,在使用线程时,将Handler用作正在启动的工作线程与主线程之间的通信方式通常也很有用。

典型的线程/处理程序交互可能看起来像这样:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

总的来说,带回家的是,您应该在执行某些可能会长时间运行或非常密集的工作(即任何网络,文件IO,繁琐的运算等)时,都应使用Thread。


感谢您的快速答复和投入的时间(以及答复速度!)!那么,让我看看我是否明白:处理程序旨在促进工作线程和UI线程之间的非阻塞通信?
JRun 2012年

3
@JRun是用途之一。请查看Java文档中的Handler描述,以获取有关它的一些不错的信息。包括它的另一种用法(安排消息和可运行对象在将来某个时刻执行)。
FoamyGuy 2012年

@FoamyGuy很好地解释了!
tony9099

嗨,是否可以保证updateUI()会在onCreateView加载新视图之后运行?
Zyoo 2013年

1
为什么呢message.what()?不是if(msg == 0){吗?非常感谢!:)
Ruchir Baronia

64

Handler和Thread实际上是两个不同的东西。

必须创建一个线程才能执行长时间运行的作业。

处理程序是在两个线程之间进行通信的非常方便的对象(例如:后台线程需要更新UI。您可以使用处理程序将一些Runnable从后台线程发布到UI线程)。

因此,您无法在Handler或Thread之间进行选择。用线程做繁重的工作!(如果您的后台线程将触发另一个线程中完成的某些工作(大多数情况下是UI线程),则可以使用Handler)


感谢您的快速答复和投入的时间(以及答复速度!)!
JRun

28

HandlerThread是两种不同的事物,但它们并不相互矛盾。您可以同时有一个Handler和一个Thread,实际上每个都Handler必须在中运行Thread

有关更多详细信息,您可能需要查看本文

在此处输入图片说明


19

A Handler在相同的线程上运行Thread,a Thread在不同的线程上运行。

如果需要在同一线程上运行某些内容,请使用处理程序(通常是GUI元素或类似的东西),。

如果您想让主线程自由执行其他操作,请使用线程。将此用于花费大量时间的任何事情。


6
如果要在同一线程上运行某些内容,为什么要使用处理程序?mHandler.post(...)方法的目的是什么?
埃里亚斯

1
Elias在这种情况下,如果您希望某个任务在一定时间后运行,或者每隔X时间重复一次任务,则可以使用处理程序。如果您不想使用这些东西,那是对的。使用处理程序是不值得的。您可以直接在其中执行GUI操作,然后,无论如何您都处于UI线程中,因为处理程序在创建它的线程上运行。
tony9099 2013年

14

处理程序是后台和UI线程之间进行通信的最佳方式。通常,处理程序与线程的消息队列相关联,它们用于发送消息并可运行到消息。

用:

线程:在saperate(Background)线程中比UI线程执行任务。(有助于解锁UI线程)

处理程序用于在UI和后台线程之间进行通信。

看看这篇文章


4

如果需要从新线程更新用户界面,则需要与用户界面线程同步。

您可以为此使用android.os.Handler类或AsyncTasks类。

Handler类可以更新用户界面。处理程序提供了用于接收Message或Runnable类的实例的方法。

您可以通过sendMessage(Message msg)方法或sendEmptyMessage()方法发布消息。

...更多信息点击这里了解线程等(包括在不同的线程和同步机制turorials以及何时使用什么)


感谢您抽出宝贵时间回答我的问题。我喜欢Lars Vogel的博客,它很有见识并且易于遵循。谢谢!
JRun

2

使用处理程序而不是线程的优点/原因是什么?

一个处理程序允许您发送和处理信息和Runnable对象与线程的关联MessageQueue。每Handler实例都与一个线程和该线程的消息队列关联。

当您创建一个新的 Handler,它将绑定到正在创建它的线程的线程/消息队列中-从那时起,它将把消息和可运行对象传递到该消息队列,并在它们从消息队列中出来时执行它们。

处理程序有两个主要用途:

  1. 计划消息和Runnable在将来的某个时刻执行
  2. 排队一个动作要在不同的线程比你自己完成。

如果使用Java线程,则必须自己处理一些事情-与主线程同步,取消线程等。

除非您使用ThreadPoolExecutorExecutorServiceAPI,否则该单个线程不会创建线程池。

(从您对Blackbelt答案的评论中选取此查询)

为什么不使用执行器?即使我确实想使用Handler来做到这一点,怎么办?

参考:线程性能文章

有些工作类型可以简化为高度并行的分布式任务。随着工作的绝对数量包,此造成的,AsyncTaskHandlerThread不是适当的类。的单线程性质AsyncTask会将所有线程池化的工作变成线性系统。HandlerThread另一方面,使用该类将要求程序员手动管理一组线程之间的负载平衡。

ThreadPoolExecutor是使该过程更容易的帮助器类。此类管理一组线程的创建,设置它们的优先级,并管理工作在这些线程之间的分配方式。随着工作负载的增加或减少,该类启动或破坏更多线程以适应工作负载。

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

您可以参考有关create-threadpool的此开发人员指南文章,以了解更多详细信息。

查看这篇文章,了解Handler如何运行多个Runnable实例。在这种情况下,所有Runnable任务将在单个线程中运行。

Android:在线程中吐司


1

Handler可以与一起使用Thread以创建排队机制。您可以使用Uou handlerThread Looper


感谢您抽出宝贵的时间回答我的问题。为什么不使用执行器?即使我确实想使用Handler来做到这一点,怎么办?
JRun 2012年

执行器有点不同。为了使用它,您必须扩展线程并在运行中调用Looper类的static.metohd prepare.。之后你调用一个队列创建的静态方法循环,您可以使用handlerbin为了向前requestes并得到返回结果
黑带
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.