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框架中找到幾乎相同的機制。

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