Handler,Runnable和Threads有什么不同?

时间:2014-01-17 19:59:19

标签: java android multithreading android-asynctask thread-safety

Handler,Runnable和Threads有什么区别?

当我使用android时,我需要在后台运行一些东西。我使用Threads来运行它。通常我会编写一个扩展Thread的类并实现run方法。

我还看到了一些可以运行的implments并将runnable传递给Threads的例子。

然而我仍然感到困惑。有人能给我一个明确的解释吗?

  1. 如果可以在Thread的run方法中编写后台代码,Runnable有什么意义?
  2. Handler如何在内部线程中使用,为什么我们需要使用它。
  3. Android还有另外一个叫runOnUiThread的东西,我们怎么用呢?我知道它用于更新UI。

6 个答案:

答案 0 :(得分:23)

为什么在线程上使用Runnable?

  • Runnable分隔需要异步运行的代码,从如何运行代码。这使您的代码保持灵活性。例如,runnable中的异步代码可以在线程池或专用线程上运行。

    Thread表示您的runnable可能不需要访问权限。获得更多不必要的状态是糟糕的设计。

    线程占用大量内存。为每个小动作创建一个新线程需要花费一些时间来分配和释放这个内存。

runOnUiThread究竟在做什么?

  • Android runOnUiThread将一个Runnable队列在UI线程上执行。这很重要,因为您永远不应该从多个线程更新UI。 runOnUiThread使用Handler

    请注意,如果UI线程的队列已满,或者需要执行的项目很长,可能需要一段时间才能排队Runnable实际运行。

什么是处理程序?

  • 处理程序允许您发布runnables以在特定线程上执行。在幕后,runOnUi Thread使用Android的Ui Handler将你的Runnable排队,这样你的runnable就可以在UI线程上安全地执行。

答案 1 :(得分:10)

<强> 1。为什么要跑?

Runnable只是一个实例化线程以包含它的接口。而线程已经包含了生成线程的能力。如果扩展Thread,则不能扩展其他任何东西(Java不支持多重继承)。您可以在类上拥有多个接口,因此您可以拥有Runnable。

此外,当您扩展Thread类时,每个线程都会创建唯一对象并与之关联。当您实现Runnable时,它将同一个对象共享给多个线程。

<强> 2。为什么要使用处理程序,它是什么?

Handler是用Java编写的(内部使用一个Thread),所以你可以用Handler做的一切,你也可以用Thread实现。

那你为什么要使用Handler?原因如下

  • Handler允许您发送和处理Message和Runnable对象 与线程的MessageQueue相关联。简单来说, 处理程序使您的工作变得轻松。

  • Android有两个处理线程的主要规则:

  • 不要阻止UI线程

  • 不要从UI线程外部访问Android UI工具包

要按照上面提到的2条规则进行绑定,在android中我们有3个内置方法可以处理当一个Activity类在不同线程上运行或调用时的情况。

然后,我们可以使用以下三种方法安排UI更新在UI线程上运行。然后,Activity或View作为处理程序(下面的处理程序更多)并将runnable安排到UI线程:

  1. Activity.runOnUiThread(可运行)
    1. View.post(Runnable)
    2. View.postDelayed(Runnable,long)//(long =调度时间)
  2. 第3。什么是UI线程?

    UI线程是呈现视图和活动等UI元素的主线程。任何耗时的操作都不应该在UI线程中发生。应用程序默认值在UI Thread中运行。您无需执行任何特殊操作UI线程。

答案 2 :(得分:4)

Handler,Runnable和Threads实际上是一起工作的,我不认为你应该比较它们。

  

处理程序

允许以安全的方式在两个线程之间发送消息,这意味着发送线程将消息放入目标线程队列,并且此目标队列将在适当的时间处理此消息。

  

可运行

这是一个你实现的接口,在实现中你将逻辑放在某个线程上。实际上,您也可以在非线程相关的位置使用Runnable。很多Java apis实际上都使用Runnable,而不仅仅是Thread。您可以使用处理程序发布Runnable,也可以将其与执行程序一起使用。 Runnables很不错,因为你可以以匿名实现的形式实现它们。

  

UniThread

你的意思是UI线程?大多数用户界面在单线程中实现其工作,所有UI元素:windows / widgets使用消息进行通信(就像在Handler中一样)。 IE浏览器。用户按下按钮,这将启动一条消息,其中包含按下按钮的信息,它将发送到UI线程,最后传送给您的监听器。

在Android中,禁止(导致异常)从非UI线程修改UI元素,这是有道理的 - 如果你要从其他线程修改它,这可能发生在UI线程对同一个小部件进行一些更改时 - 结果在未定义的行为中。

答案 3 :(得分:1)

  

我使用Threads来运行它。通常我会编写一个扩展Thread的类并实现run方法。

     

1.如果可以在Thread的run方法中编写后台代码,Runnable的重点是什么?

使用Runnable并从Runnable创建线程是一般做法。

关于RunnableThread用法的concurrency上的oracle教程:

Runnable对象,更通用,因为Runnable对象可以继承Thread以外的类。

  

2.如何在内部线程中使用Handler,为什么我们需要使用它。

这是一个很难解释的话题。简而言之,来自官方文档网站:

  1. Handler允许您发送和处理与帖子Message相关联的RunnableMessageQueue个对象。每个Handler实例都与一个线程和该线程的消息队列相关联。

  2. 当你创建一个新的Handler时,它被绑定到正在创建它的线程的线程/消息队列 - 从那时起,它将传递消息和runnables到该消息队列在它们从消息队列中出来时执行它们。

  3. Handler有两个主要用途:(1)将消息和runnable安排在将来的某个点上执行; (2)将要在不同于自己的线程上执行的动作排入队列

  4. 为应用程序创建进程时,其主线程专用于运行消息队列,该队列负责管理顶级应用程序对象(活动,广播接收器等)及其创建的任何窗口。 您可以创建自己的线程,并通过处理程序与主应用程序线程进行通信。 这可以通过调用与以前相同的帖子或sendMessage方法来完成,但是从你的新线程。然后,将在Handler的消息队列中安排给定的Runnable或Message,并在适当的时候进行处理。

  5. Anishar Ali的blog.mindorks.com文章中的这张照片清楚地解释了概念。

    enter image description here

      

    3.Android还有一个叫runOnUiThread的东西,我们怎么用呢?我知道它用于更新UI。

    您可以通过查看runOnUiThread

    的实施来查找更多详细信息
    /**
         * Runs the specified action on the UI thread. If the current thread is the UI
         * thread, then the action is executed immediately. If the current thread is
         * not the UI thread, the action is posted to the event queue of the UI thread.
         *
         * @param action the action to run on the UI thread
         */
        public final void runOnUiThread(Runnable action) {
            if (Thread.currentThread() != mUiThread) {
                mHandler.post(action);
            } else {
                action.run();
            }
        }
    

    有关Handler用法的示例代码,请参阅以下帖子。

    Android: Toast in a thread

答案 4 :(得分:0)

  

如果可以编写后台代码,Runnable有什么意义呢?   Thread的run方法?

Runnable是一个接口,用于创建一个类似于通过扩展java.lang.Thread类创建的线程类的新线程类。唯一不同的是,Runnable接口允许类扩展其他类(如果需要)以覆盖/继承某些类的功能。扩展java.lang.Thread类将撤销此功能。

此外,Runnable接口表示可以由普通线程或执行器或任何其他方式执行的任务。所以将Task作为Runnable与Thread进行逻辑分离是一个很好的设计决策。

了解详情:http://javarevisited.blogspot.com/2012/01/difference-thread-vs-runnable-interface.html#ixzz2qgjDYJhT

答案 5 :(得分:0)

Runnable接口是Thread类的父级,而run()是Runnable接口的方法 所以通常我们应该选择Runnable接口而不是扩展线程类,因为我们不想更改该类的行为,我们还可以扩展另一个类,这也有助于实现松散耦合,并且可以受益于更改用户界面来自任何其他阶层。

我们可以通过4种方式更改Ui

1。通过使用Handler示例

public class MainActivity extends AppCompatActivity {    
private Handler mainHandler=new Handler();
class ExampleRunnable implements Runnable {
        int seconds;

        public ExampleRunnable(int seconds) {
            this.seconds = seconds;
        }

        @Override
        public void run() {
            for (int i = 0; i < seconds; i++) {
 mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                        button.setText("50% process completed");
                        }
                    });

2。通过使用runOnUIThread(),我们必须将runOnUIThread附加到示例中,可以通过示例轻松理解

class ExampleRunnable implements Runnable {
        int seconds;



 public ExampleRunnable(int seconds) {
        this.seconds = seconds;
    }

    @Override
    public void run() {runOnUIThread.post(new Runnable() {
                    @Override
                    public void run() {
                        button.setText(" Runnable");
                    }
                });
            }

3。通过使用任何视图,我们都可以在这里通过开关调用的任何视图调用

public class MainActivity extends AppCompatActivity {
 private Switch aSwitch;
@Override
    protected void onCreate(Bundle savedInstanceState) {
 aSwitch=findViewById(R.id.switch1);
class ExampleRunnable implements Runnable {
            int seconds;



     public ExampleRunnable(int seconds) {
            this.seconds = seconds;
        }

        @Override
        public void run() { aSwitch.post(new Runnable() {
                        @Override
                        public void run() {
                            button.setText(" Runnable");
                        }
                    });
                }

4。通过在另一个线程中创建Handler,我们必须定义Looper,因为默认情况下它将其附加到我们的线程Looper中

Handler threadHandler=new Handler(Looper.getMainLooper());
threadHandler.post(new Runnable()
{
                            @Override
                            public void run() {
                                button.setText(" Runnable");
                            }
                        });
                    }

这是4种实现方式,因此我认为您现在可以对可运行线程和runOnUIThread()有所了解,而Handler是由其他人精美编写的。