Looper的目的是什么以及如何使用它?

本文翻译自:What is the purpose of Looper and how to use it?

I am new to Android. 我是Android新手。 I want to know what the Looper class does and also how to use it. 我想知道Looper类的功能以及如何使用它。 I have read the Android Looper class documentation but I am unable to completely understand it. 我已阅读Android Looper类文档,但我无法完全理解它。 I have seen it in a lot of places but unable to understand its purpose. 我在很多地方都看过它但却无法理解它的目的。 Can anyone help me by defining the purpose of Looper and also by giving a simple example if possible? 任何人都可以通过定义Looper的目的来帮助我,并且如果可能的话也给出一个简单的例子吗?


#1楼

参考:https://stackoom.com/question/VsWE/Looper的目的是什么以及如何使用它


#2楼

Handling multiple down or upload items in a Service is a better example. 在处理多个向下或上传项目服务是一个更好的例子。

Handler and AsnycTask are often used to propagate Events/Messages between the UI (thread) and a worker thread or to delay actions. HandlerAsnycTask通常用于在UI(线程)和工作线程之间传播事件/消息或延迟操作。 So they are more related to UI. 所以他们与UI更相关。

A Looper handles tasks ( Runnables, Futures ) in a thread related queue in the background - even with no user interaction or a displayed UI (app downloads a file in the background during a call). Looper在后台处理线程相关队列中的任务( Runnables,Futures ) - 即使没有用户交互或显示的UI(app在调用期间在后台下载文件)。


#3楼

Android Looper is a wrapper to attach MessageQueue to Thread and it manages Queue processing. Android Looper是一个将MessageQueue附加到Thread的包装器,它管理队列处理。 It looks very cryptic in Android documentation and many times we may face Looper related UI access issues. 它在Android文档中看起来非常神秘,很多时候我们可能会遇到与Looper相关的UI访问问题。 If we don't understand the basics it becomes very tough to handle. 如果我们不了解基础知识就很难处理。

Here is an article which explains Looper life cycle, how to use it and usage of Looper in Handler 这篇文章解释了Looper生命周期,如何使用它以及在Handler使用Looper

在此输入图像描述

Looper = Thread + MessageQueue Looper = Thread + MessageQueue


#4楼

Looper allows tasks to be executed sequentially on a single thread. Looper允许在单个线程上顺序执行任务。 And handler defines those tasks that we need to be executed. 并且处理程序定义了我们需要执行的那些任务。 It is a typical scenario that I am trying to illustrate in this example: 这是一个典型的场景,我试图在这个例子中说明:

class SampleLooper extends Thread {
@Override
public void run() {
  try {
    // preparing a looper on current thread     
    // the current thread is being detected implicitly
    Looper.prepare();

    // now, the handler will automatically bind to the
    // Looper that is attached to the current thread
    // You don't need to specify the Looper explicitly
    handler = new Handler();

    // After the following line the thread will start
    // running the message loop and will not normally
    // exit the loop unless a problem happens or you
    // quit() the looper (see below)
    Looper.loop();
  } catch (Throwable t) {
    Log.e(TAG, "halted due to an error", t);
  } 
}
}

Now we can use the handler in some other threads(say ui thread) to post the task on Looper to execute. 现在我们可以在其他一些线程(比如ui线程)中使用处理程序在Looper上发布任务来执行。

handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
    }
});

On UI thread we have an implicit Looper that allow us to handle the messages on ui thread. 在UI线程上,我们有一个隐式Looper,允许我们处理ui线程上的消息。


#5楼

A Looper has a synchronized MessageQueue that's used to process Messages placed on the queue. Looper有一个synchronized MessageQueue ,用于处理放在队列中的消息。

It implements a Thread Specific Storage Pattern. 它实现了特定于Thread存储模式。

Only one Looper per Thread . 每个Thread只有一个Looper Key methods include prepare() , loop() and quit() . 关键方法包括prepare()loop()quit()

prepare() initializes the current Thread as a Looper . prepare()将当前Thread初始化为Looper prepare() is static method that uses the ThreadLocal class as shown below. prepare()是使用ThreadLocal类的static方法,如下所示。

   public static void prepare(){
       ...
       sThreadLocal.set
       (new Looper());
   }
  1. prepare() must be called explicitly before running the event loop. 必须在运行事件循环之前显式调用prepare()
  2. loop() runs the event loop which waits for Messages to arrive on a specific Thread's messagequeue. loop()运行事件循环,等待消息到达特定线程的消息队列。 Once the next Message is received,the loop() method dispatches the Message to its target handler 收到下一条消息后, loop()方法将Message调度到其目标处理程序
  3. quit() shuts down the event loop. quit()关闭事件循环。 It doesn't terminate the loop,but instead it enqueues a special message 它不会终止循环,而是将特殊消息排入队列

Looper can be programmed in a Thread via several steps Looper可以通过几个步骤在Thread编程

  1. Extend Thread 扩展Thread

  2. Call Looper.prepare() to initialize Thread as a Looper 调用Looper.prepare()将Thread初始化为Looper

  3. Create one or more Handler (s) to process the incoming messages 创建一个或多个Handler程序以处理传入的消息

  4. Call Looper.loop() to process messages until the loop is told to quit() . 调用Looper.loop()来处理消息,直到告诉循环quit()

#6楼

You can better understand what Looper is in the context of GUI framework. 您可以更好地了解Looper在GUI框架中的作用。 Looper is made to do 2 things. Looper是做两件事的。

1) Looper transforms a normal thread , which terminates when its run() method return, into something run continuously until Android app is running , which is needed in GUI framework (Technically, it still terminates when run() method return. But let me clarify what I mean in below). 1)Looper 将一个正常的线程转换为一个正常的线程 ,该线程在run()方法返回时终止, 直到Android应用程序运行直到运行 ,这在GUI框架中是必需的(从技术上讲,它仍然在run()方法返回时终止。但是让我澄清我在下面的意思)。

2) Looper provides a queue where jobs to be done are enqueued, which is also needed in GUI framework. 2)Looper 提供了一个队列 ,其中要完成的作业被排队,这在GUI框架中也是必需的。

As you may know, when an application is launched, the system creates a thread of execution for the application, called “main”, and Android applications normally run entirely on a single thread by default the “main thread”. 您可能知道,当启动应用程序时,系统会为应用程序创建一个执行线程,称为“main”,而Android应用程序通常完全在单个线程上运行,默认情况下为“主线程”。 But main thread is not some secret, special thread . 主线程不是一些秘密,特殊线程 It's just a normal thread similar to threads you create with new Thread() code, which means it terminates when its run() method return! 它只是一个普通的线程,类似于你用new Thread()代码创建的new Thread() ,这意味着它在run()方法返回时终止! Think of below example. 想想下面的例子。

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

Now, let's apply this simple principle to Android apps. 现在,让我们将这个简单的原则应用于Android应用程序。 What would happen if an Android app runs on normal thread? 如果Android应用程序在正常线程上运行会发生什么? A thread called "main" or "UI" or whatever starts your application, and draws all UI. 一个名为“main”或“UI”的线程或任何启动应用程序的线程,并绘制所有UI。 So, the first screen is displayed to users. 因此,第一个屏幕显示给用户。 So what now? 所以现在怎么办? The main thread terminates? 主线程终止了吗? No, it shouldn't. 不,它不应该。 It should wait until users do something, right? 它应该等到用户做某事,对吧? But how can we achieve this behavior? 但是我们怎样才能实现这种行为呢? Well, we can try with Object.wait() or Thread.sleep() . 好吧,我们可以尝试使用Object.wait()Thread.sleep() For example, main thread finishes its initial job to display first screen, and sleeps. 例如,主线程完成其初始作业以显示第一个屏幕,然后休眠。 It awakes, which means interrupted, when a new job to do is fetched. 当需要执行新工作时,它会唤醒,这意味着中断。 So far so good, but at this moment we need a queue-like data structure to hold multiple jobs. 到目前为止一切顺利,但此时我们需要一个类似队列的数据结构来保存多个作业。 Think about a case when a user touches screen serially, and a task takes longer time to finish. 想想用户连续触摸屏幕的情况,任务需要更长的时间才能完成。 So, we need to have a data structure to hold jobs to be done in first-in-first-out manner. 因此,我们需要一个数据结构来保持以先进先出的方式完成的工作。 Also, you may imagine, implementing ever-running-and-process-job-when-arrived thread using interrupt is not easy, and leads to complex and often unmaintainable code. 此外,您可以想象,使用中断实现永远运行和进程的作业到达线程并不容易,并导致复杂且通常无法维护的代码。 We'd rather create a new mechanism for such purpose, and that is what Looper is all about . 我们宁愿为此目的创建一个新机制, 这就是Looper的意义所在 The official document of Looper class says, "Threads by default do not have a message loop associated with them", and Looper is a class "used to run a message loop for a thread". Looper类官方文档说,“默认情况下,线程没有与它们相关的消息循环”,而Looper是一个“用于为线程运行消息循环”的类。 Now you can understand what it means. 现在你可以理解它的含义了。

To make things more clear, let's check the code where main thread is transformed. 为了使事情更清楚,让我们检查主线程转换的代码。 It all happens in ActivityThread class . 这一切都发生在ActivityThread类中 In its main() method, you can find below code, which turns a normal main thread into something what we need. 在main()方法中,您可以找到下面的代码,它将正常的主线程转换为我们需要的东西。

public final class ActivityThread {
    ...
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        Looper.loop();
        ...
    }
}

and Looper.loop() method loop infinitely and dequeue a message and process one at a time: Looper.loop()方法无限循环并将​​消息出列并一次处理一个消息:

public static void loop() {
    ...
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ...
        msg.target.dispatchMessage(msg);
        ...
    }
}

So, basically Looper is a class that is made to address a problem that occurs in GUI framework. 因此,基本上Looper是一个用于解决GUI框架中出现的问题的类。 But this kind of needs can also happen in other situation as well. 但是这种需求也可能在其他情况下发生。 Actually it is a pretty famous pattern for multi threads application, and you can learn more about it in " Concurrent Programming in Java " by Doug Lea(Especially, chapter 4.1.4 "Worker Threads" would be helpful). 实际上它是一个非常着名的多线程应用程序模式,你可以 Doug Lea的“ Concurrent Programming in Java ”中了解它(特别是第4.1.4节“工作线程”会很有帮助)。 Also, you can imagine this kind of mechanism is not unique in Android framework, but all GUI framework may need somewhat similar to this. 此外,您可以想象这种机制在Android框架中并不是唯一的,但是所有GUI框架可能都需要与此类似。 You can find almost same mechanism in Java Swing framework. 您可以在Java Swing框架中找到几乎相同的机制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章