Mục đích của Looper là gì và làm thế nào để sử dụng nó?


454

Tôi mới sử dụng Android. Tôi muốn biết những gì Looperlớp làm và cũng làm thế nào để sử dụng nó. Tôi đã đọc tài liệu lớp Android Looper nhưng tôi không thể hiểu nó hoàn toàn. Tôi đã nhìn thấy nó ở rất nhiều nơi nhưng không thể hiểu mục đích của nó. Bất cứ ai có thể giúp tôi bằng cách xác định mục đích Loopervà cũng bằng cách đưa ra một ví dụ đơn giản nếu có thể?


7
Tôi vừa tìm thấy một lời giải thích cực kỳ kỹ lưỡng và rõ ràng về Looper và việc sử dụng nó trên Safari Books Online. Thật không may, tôi nghi ngờ truy cập nếu miễn phí trong một thời gian giới hạn. safaribooksonline.com/l Library / view / hiệu quả
Joe Lapp

1
Các bài viết và trang tham khảo trên Android yêu cầu bạn phải có và hiểu về bài viết trước, trước khi bạn có thể nắm bắt bài viết hiện tại. Tôi đề nghị bạn đọc các bài viết Hoạt động và Dịch vụ trong hướng dẫn Api, sau đó đọc Handler và Looper. Nó cũng hữu ích nếu bạn có một sự hiểu biết về một chủ đề là gì (không phải là một chủ đề Android, mà là một chủ đề nói chung ... ví dụ POSIX).
FutureSci

1
Tôi thấy bài viết này hữu ích: codetheory.in/ từ
Herman

Câu trả lời:


396

Looper là gì?

Looper là một lớp được sử dụng để thực thi các Tin nhắn (Runnables) trong hàng đợi. Chủ đề bình thường không có hàng đợi như vậy, ví dụ chủ đề đơn giản không có bất kỳ hàng đợi. Nó thực thi một lần và sau khi thực hiện phương thức kết thúc, luồng sẽ không chạy một Thông báo khác (Runnable).

Chúng ta có thể sử dụng lớp Looper ở đâu?

Nếu ai đó muốn thực thi nhiều tin nhắn (Runnables) thì anh ta nên sử dụng lớp Looper chịu trách nhiệm tạo hàng đợi trong luồng. Ví dụ, trong khi viết một ứng dụng tải tệp từ internet, chúng ta có thể sử dụng lớp Looper để đặt các tệp được tải xuống trong hàng đợi.

Làm thế nào nó hoạt động?

prepare()phương pháp để chuẩn bị Looper. Sau đó, bạn có thể sử dụng loop()phương thức để tạo một vòng lặp thông báo trong luồng hiện tại và bây giờ Looper của bạn đã sẵn sàng để thực hiện các yêu cầu trong hàng đợi cho đến khi bạn thoát khỏi vòng lặp.

Đây là mã mà bạn có thể chuẩn bị Looper.

class LooperThread extends Thread {
      public Handler mHandler;

      @Override
      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              @Override
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

17
AsyncTask tốt hơn cho mục đích đó và ít phức tạp hơn vì nó gói gọn tất cả các quản lý luồng.
Fernando Gallego

4
Nên có các chú thích @Override trước các phương thức run () và handleMessage ()
Andrew Mackenzie

5
Các tài liệu chỉ ra rằng bạn phải gọi looper.quito. Trong mã của bạn ở trên, Looper.loop sẽ chặn vô thời hạn.
AndroidDev

2
Làm thế nào để thoát khỏi một vòng lặp. Tôi có nghĩa là nơi để bao gồm Looper.quito () trong ví dụ mã ở trên?
Seenu69

6
Tôi nghĩ sẽ tốt hơn nếu sử dụng HandlerThread , đây là một lớp thuận tiện cho một luồng với một kẻ lừa đảo.
Nimrod Dayan

287

Bạn có thể hiểu rõ hơn Looper là gì trong bối cảnh GUI GUI. Looper được thực hiện để làm 2 việc.

1) Looper biến đổi một luồng bình thường , kết thúc khi phương thức run () của nó trở lại, thành một thứ gì đó chạy liên tục cho đến khi ứng dụng Android chạy , cần thiết trong khung GUI (Về mặt kỹ thuật, nó vẫn chấm dứt khi phương thức run () quay lại. làm rõ những gì tôi muốn nói ở bên dưới)

2) Looper cung cấp một hàng đợi trong đó các công việc phải hoàn thành được yêu cầu, điều này cũng cần thiết trong khung GUI.

Như bạn có thể biết, khi một ứng dụng được khởi chạy, hệ thống sẽ tạo ra một luồng thực thi cho ứng dụng, được gọi là chính main, và các ứng dụng Android thường chạy hoàn toàn trên một luồng theo mặc định là chủ đề chính của chanh. Nhưng chủ đề chính không phải là một số chủ đề bí mật, đặc biệt . Nó chỉ là một luồng bình thường tương tự như các luồng bạn tạo bằng new Thread()mã, có nghĩa là nó kết thúc khi phương thức run () của nó trả về! Hãy nghĩ về ví dụ dưới đây.

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();
    }
}

Bây giờ, hãy áp dụng nguyên tắc đơn giản này cho các ứng dụng Android. Điều gì sẽ xảy ra nếu một ứng dụng Android chạy trên luồng bình thường? Một chuỗi được gọi là "chính" hoặc "Giao diện người dùng" hoặc bất cứ điều gì khởi động ứng dụng của bạn và rút ra tất cả giao diện người dùng. Vì vậy, màn hình đầu tiên được hiển thị cho người dùng. Giờ thì sao? Chủ đề chính chấm dứt? Không, nó không nên. Nó sẽ đợi cho đến khi người dùng làm một cái gì đó, phải không? Nhưng làm thế nào chúng ta có thể đạt được hành vi này? Vâng, chúng ta có thể thử với Object.wait()hoặcThread.sleep(). Ví dụ, luồng chính hoàn thành công việc ban đầu để hiển thị màn hình đầu tiên và ngủ. Nó thức dậy, có nghĩa là bị gián đoạn, khi một công việc mới phải làm được tìm nạp. Cho đến nay là tốt, nhưng tại thời điểm này, chúng ta cần một cấu trúc dữ liệu giống như hàng đợi để giữ nhiều công việc. Hãy suy nghĩ về một trường hợp khi người dùng chạm vào màn hình một cách thanh thản và một tác vụ mất nhiều thời gian hơn để hoàn thành. Vì vậy, chúng ta cần phải có một cấu trúc dữ liệu để giữ các công việc phải được thực hiện theo cách trước xuất trước. Ngoài ra, bạn có thể tưởng tượng, việc thực hiện luồng luôn chạy và xử lý công việc khi đến bằng cách sử dụng ngắt là không dễ dàng, và dẫn đến mã phức tạp và thường không thể nhầm lẫn. Chúng tôi muốn tạo ra một cơ chế mới cho mục đích như vậy và đó là tất cả những gì Looper hướng tới . Các tài liệu chính thức của lớp Loopernói, "Chủ đề theo mặc định không có vòng lặp thông báo liên quan đến chúng" và Looper là một lớp "được sử dụng để chạy vòng lặp thông báo cho một chuỗi". Bây giờ bạn có thể hiểu ý nghĩa của nó.

Để làm cho mọi thứ rõ ràng hơn, hãy kiểm tra mã nơi chuyển đổi luồng chính. Tất cả xảy ra trong lớp ActivityThread . Trong phương thức main () của nó, bạn có thể tìm thấy đoạn mã bên dưới, biến một luồng chính bình thường thành thứ chúng ta cần.

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

Looper.loop()phương thức lặp vô hạn và xử lý một thông báo và xử lý từng thông báo một:

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);
        ...
    }
}

Vì vậy, về cơ bản Looper là một lớp được tạo ra để giải quyết vấn đề xảy ra trong khung GUI. Nhưng loại nhu cầu này cũng có thể xảy ra trong tình huống khác. Trên thực tế, đây là một mẫu khá nổi tiếng cho ứng dụng đa luồng và bạn có thể tìm hiểu thêm về nó trong " Lập trình đồng thời trong Java " của Doug Lea (Đặc biệt, chương 4.1.4 "Chủ đề công nhân" sẽ hữu ích). Ngoài ra, bạn có thể tưởng tượng loại cơ chế này không phải là duy nhất trong khung Android, nhưng tất cả khung GUI có thể cần hơi giống với điều này. Bạn có thể tìm thấy cơ chế gần như tương tự trong khung công tác Java Swing.


26
Đây là câu trả lời duy nhất thực sự giải thích bất cứ điều gì về lý do tại sao lớp Looper sẽ được sử dụng. Tôi không chắc tại sao nó không phải là câu trả lời hàng đầu, ba câu trả lời được đánh giá cao hơn không giải thích gì.
Andrew Koster

4
@AK. Đó là lý do tại sao tôi thêm câu trả lời này ngay cả khi nó dường như quá muộn. Tôi rất vui vì câu trả lời của tôi đã giúp bạn! :)
김준호

1
@ Hey-men-WhatsUp Có
김준호

1
Trước khi đọc điều này tôi giống như "Looper ???" và bây giờ "Ồ vâng, hãy thảo luận về nó". Cảm ơn người đàn ông, câu trả lời tuyệt vời :)
umerk44

Câu hỏi nhanh. Bạn đã nói rằng trong luồng chính sau khi nó rút ra tất cả các thành phần UI, nó được đưa vào chế độ ngủ. Nhưng giả sử người dùng tương tác với một nút trên màn hình, không phải nút đó nhấp vào thậm chí đưa vào hàng đợi chính, sau đó một đối tượng sẽ gửi nó đến hoạt động chính xác, sau đó luồng chính cho hoạt động đó đã thức và nó sẽ thực thi mã cho trong cuộc gọi lại cho nút đó nhấp vào?
CapturedTree

75

Looper cho phép các tác vụ được thực hiện tuần tự trên một luồng. Và xử lý xác định những nhiệm vụ mà chúng ta cần phải được thực hiện. Đó là một kịch bản điển hình mà tôi đang cố gắng minh họa trong ví dụ này:

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);
  } 
}
}

Bây giờ chúng ta có thể sử dụng trình xử lý trong một số luồng khác (giả sử luồng ui) để đăng tác vụ lên Looper để thực thi.

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

Trên luồng UI, chúng ta có một Looper ẩn cho phép chúng ta xử lý các thông điệp trên luồng ui.


Nó sẽ không khóa bất kỳ Quá trình UI nào, có đúng không?
gumuruh

4
Cảm ơn vì đã bao gồm mẫu về cách đăng "công việc" lên hàng đợi
Peter Lillevold

Điều này không giải thích tại sao một người sẽ sử dụng lớp này, chỉ làm thế nào.
Andrew Koster

33

Android Looperlà một wrapper để đính kèm MessageQueuevào Threadvà nó quản lý chế biến Queue. Nó trông rất khó hiểu trong tài liệu Android và nhiều lần chúng ta có thể phải đối mặt với Loopercác vấn đề truy cập UI liên quan. Nếu chúng ta không hiểu những điều cơ bản thì sẽ rất khó xử lý.

Dưới đây là một bài viết giải thích về Loopervòng đời, cách sử dụng và sử dụng LoopertrongHandler

nhập mô tả hình ảnh ở đây

Looper = Chủ đề + MessageQueue


3
Điều này không giải thích tại sao một người sẽ sử dụng lớp này, chỉ làm thế nào.
Andrew Koster

14

Định nghĩa của Looper & Handler:

Looper là một lớp biến một luồng thành một Pipeline ThreadHandler cung cấp cho bạn một cơ chế để đẩy các tác vụ vào nó từ bất kỳ luồng nào khác.

Chi tiết:

Vì vậy, một TubeLine Thread là một luồng có thể chấp nhận nhiều tác vụ hơn từ các luồng khác thông qua Handler.

Các Looper được đặt tên như vậy bởi vì nó thực hiện các vòng lặp - mất nhiệm vụ tiếp theo, thực hiện nó, sau đó sẽ đưa người tiếp theo và như vậy. Handler được gọi là handler vì nó được sử dụng để xử lý hoặc chấp nhận nhiệm vụ tiếp theo mỗi lần từ bất kỳ luồng nào khác và chuyển đến Looper (Thread hoặc TubeLine Thread).

Thí dụ:

Một ví dụ rất hoàn hảo của Looper và Handler hoặc TubeLine Thread là tải xuống nhiều hình ảnh hoặc tải chúng lên máy chủ (http) từng cái một trong một luồng thay vì bắt đầu một Chủ đề mới cho mỗi cuộc gọi mạng trong nền.

Đọc thêm ở đây về Looper và Handler và định nghĩa của Pipeline Thread:

Android Guts: Giới thiệu về Loopers và Handlers


7

Một Looper có một synchronized MessageQueuecái được sử dụng để xử lý Tin nhắn được đặt trên hàng đợi.

Nó thực hiện một Threadmô hình lưu trữ cụ thể.

Chỉ có một Loopercho mỗi Thread. Các phương pháp chính bao gồm prepare(), loop()quit().

prepare()khởi tạo dòng điện Threadlà a Looper. prepare()staticphương thức sử dụng ThreadLocallớp như hình bên dưới.

   public static void prepare(){
       ...
       sThreadLocal.set
       (new Looper());
   }
  1. prepare() phải được gọi rõ ràng trước khi chạy vòng lặp sự kiện.
  2. loop()chạy vòng lặp sự kiện chờ Tin nhắn đến trên thông báo của một Chủ đề cụ thể. Khi nhận được tin nhắn tiếp theo, loop()phương thức sẽ gửi tin nhắn đến bộ xử lý đích của nó
  3. quit()tắt vòng lặp sự kiện. Nó không chấm dứt vòng lặp, nhưng thay vào đó, nó đưa ra một thông điệp đặc biệt

Loopercó thể được lập trình trong một Threadvài bước

  1. Mở rộng Thread

  2. Gọi Looper.prepare()để khởi tạo Thread như mộtLooper

  3. Tạo một hoặc nhiều Handler(các) để xử lý các tin nhắn đến

  4. Gọi Looper.loop()để xử lý tin nhắn cho đến khi vòng lặp được thông báo quit().

5

Tuổi thọ của java Thread kết thúc sau khi hoàn thành run()phương thức. Cùng một chủ đề không thể được bắt đầu lại.

Looper biến đổi bình thường Threadthành một vòng lặp tin nhắn. Các phương pháp chính Looperlà:

void prepare ()

Khởi tạo chủ đề hiện tại như một looper. Điều này cung cấp cho bạn một cơ hội để tạo các trình xử lý sau đó tham chiếu bộ xử lý này, trước khi thực sự bắt đầu vòng lặp. Hãy chắc chắn gọi loop () sau khi gọi phương thức này và kết thúc nó bằng cách gọi thoát ().

void loop ()

Chạy hàng đợi tin nhắn trong chủ đề này. Hãy chắc chắn gọi thoát () để kết thúc vòng lặp.

void quit()

Thoát khỏi kẻ lừa đảo.

Làm cho phương thức loop () chấm dứt mà không xử lý thêm bất kỳ tin nhắn nào trong hàng đợi tin nhắn.

Bài viết tư duy này của J Biếnar giải thích các khái niệm cốt lõi theo cách tốt đẹp.

nhập mô tả hình ảnh ở đây

Looperđược liên kết với một chủ đề. Nếu bạn cần Looperchủ đề UI, Looper.getMainLooper()sẽ trả về chủ đề liên quan.

Bạn cần Looperphải được liên kết với một Handler .

Looper, HandlerHandlerThreadlà cách Android giải quyết các vấn đề về lập trình không đồng bộ.

Khi bạn đã có Handler, bạn có thể gọi API bên dưới.

post (Runnable r)

Làm cho r Runnable được thêm vào hàng đợi tin nhắn. Runnable sẽ được chạy trên luồng mà trình xử lý này được đính kèm.

boolean sendMessage (Message msg)

Đẩy một tin nhắn vào cuối hàng đợi tin nhắn sau tất cả các tin nhắn đang chờ xử lý trước thời điểm hiện tại. Nó sẽ được nhận trong handleMessage (Message), trong chuỗi được đính kèm với trình xử lý này.

HandlerThread là lớp tiện dụng để bắt đầu một chủ đề mới có một looper. Các looper sau đó có thể được sử dụng để tạo các lớp xử lý

Trong một số trường hợp, bạn không thể chạy Runnablecác tác vụ trên UI Thread. ví dụ: Hoạt động mạng: Gửi tin nhắn trên ổ cắm, mở URL và nhận nội dung bằng cách đọcInputStream

Trong những trường hợp này, HandlerThreadlà hữu ích. Bạn có thể lấy Looperđối tượng từ HandlerThreadvà tạo ra một Handlertrên HandlerThreadthay vì chủ đề chính.

Các HandlerThread mã sẽ được như thế này:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

Tham khảo bài viết dưới đây để biết ví dụ mã:

Android: Toast trong một chủ đề


5

Hiểu chủ đề Looper

Một java Thread một đơn vị thực thi được thiết kế để thực hiện một tác vụ trong phương thức run () của nó và chấm dứt sau đó: nhập mô tả hình ảnh ở đây

Nhưng trong Android, có nhiều trường hợp sử dụng, trong đó chúng ta cần giữ một Chủ đề tồn tại và chờ đợi các sự kiện / sự kiện đầu vào của người dùng. Giao diện người dùng aka Main Thread.

Chủ đề chính trong Android là một chủ đề Java, được JVM khởi động lần đầu tiên khi ra mắt một ứng dụng và tiếp tục chạy cho đến khi người dùng chọn đóng nó hoặc gặp ngoại lệ chưa được xử lý.

Khi một ứng dụng được khởi chạy, hệ thống sẽ tạo ra một luồng thực thi cho ứng dụng, được gọi là "chính". Chủ đề này rất quan trọng vì nó chịu trách nhiệm gửi các sự kiện đến các widget giao diện người dùng thích hợp, bao gồm cả các sự kiện vẽ.

nhập mô tả hình ảnh ở đây

Bây giờ điểm cần lưu ý ở đây là mặc dù luồng chính là luồng Java nhưng nó vẫn tiếp tục lắng nghe các sự kiện của người dùng và vẽ 60 khung hình / giây trên màn hình và nó vẫn không chết sau mỗi chu kỳ. Làm thế nào là như vậy?

Câu trả lời là Looper Class : Looper là một lớp được sử dụng để giữ một luồng tồn tại và quản lý hàng đợi tin nhắn để thực thi các tác vụ trên luồng đó.

Các chủ đề theo mặc định không có vòng lặp thông báo được liên kết với chúng nhưng bạn có thể chỉ định một chủ đề bằng cách gọi Looper.prepare () trong phương thức chạy và sau đó gọi Looper.loop ().

Mục đích của Looper là giữ cho một luồng tồn tại và chờ cho chu kỳ tiếp theo của Messageđối tượng đầu vào thực hiện tính toán, nếu không sẽ bị phá hủy sau chu kỳ thực hiện đầu tiên.

Nếu bạn muốn tìm hiểu sâu hơn về cách Looper quản lý Messagehàng đợi đối tượng thì bạn có thể xem mã nguồn của Looperclass:

https://github.com/aosp-mirror/pl platform_frameworks_base/blob/master/core/java/android/os/Looper.java

Dưới đây là một ví dụ về cách bạn có thể tạo Looper Threadvà giao tiếp với Activitylớp bằng cách sử dụngLocalBroadcast

class LooperThread : Thread() {

    // sendMessage success result on UI
    private fun sendServerResult(result: String) {
        val resultIntent = Intent(ServerService.ACTION)
        resultIntent.putExtra(ServerService.RESULT_CODE, Activity.RESULT_OK)
        resultIntent.putExtra(ServerService.RESULT_VALUE, result)
        LocalBroadcastManager.getInstance(AppController.getAppController()).sendBroadcast(resultIntent)
    }

    override fun run() {
        val looperIsNotPreparedInCurrentThread = Looper.myLooper() == null

        // Prepare Looper if not already prepared
        if (looperIsNotPreparedInCurrentThread) {
            Looper.prepare()
        }

        // Create a handler to handle messaged from Activity
        handler = Handler(Handler.Callback { message ->
            // Messages sent to Looper thread will be visible here
            Log.e(TAG, "Received Message" + message.data.toString())

            //message from Activity
            val result = message.data.getString(MainActivity.BUNDLE_KEY)

            // Send Result Back to activity
            sendServerResult(result)
            true
        })

        // Keep on looping till new messages arrive
        if (looperIsNotPreparedInCurrentThread) {
            Looper.loop()
        }
    }

    //Create and send a new  message to looper
    fun sendMessage(messageToSend: String) {
        //Create and post a new message to handler
        handler!!.sendMessage(createMessage(messageToSend))
    }


    // Bundle Data in message object
    private fun createMessage(messageToSend: String): Message {
        val message = Message()
        val bundle = Bundle()
        bundle.putString(MainActivity.BUNDLE_KEY, messageToSend)
        message.data = bundle
        return message
    }

    companion object {
        var handler: Handler? = null // in Android Handler should be static or leaks might occur
        private val TAG = javaClass.simpleName

    }
}

Cách sử dụng :

 class MainActivity : AppCompatActivity() {

    private var looperThread: LooperThread? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // start looper thread
        startLooperThread()

        // Send messages to Looper Thread
        sendMessage.setOnClickListener {

            // send random messages to looper thread
            val messageToSend = "" + Math.random()

            // post message
            looperThread!!.sendMessage(messageToSend)

        }   
    }

    override fun onResume() {
        super.onResume()

        //Register to Server Service callback
        val filterServer = IntentFilter(ServerService.ACTION)
        LocalBroadcastManager.getInstance(this).registerReceiver(serverReceiver, filterServer)

    }

    override fun onPause() {
        super.onPause()

        //Stop Server service callbacks
     LocalBroadcastManager.getInstance(this).unregisterReceiver(serverReceiver)
    }


    // Define the callback for what to do when data is received
    private val serverReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val resultCode = intent.getIntExtra(ServerService.RESULT_CODE, Activity.RESULT_CANCELED)
            if (resultCode == Activity.RESULT_OK) {
                val resultValue = intent.getStringExtra(ServerService.RESULT_VALUE)
                Log.e(MainActivity.TAG, "Server result : $resultValue")

                serverOutput.text =
                        (serverOutput.text.toString()
                                + "\n"
                                + "Received : " + resultValue)

                serverScrollView.post( { serverScrollView.fullScroll(View.FOCUS_DOWN) })
            }
        }
    }

    private fun startLooperThread() {

        // create and start a new LooperThread
        looperThread = LooperThread()
        looperThread!!.name = "Main Looper Thread"
        looperThread!!.start()

    }

    companion object {
        val BUNDLE_KEY = "handlerMsgBundle"
        private val TAG = javaClass.simpleName
    }
}

Thay vào đó, chúng ta có thể sử dụng tác vụ Async hoặc Intent Services không?

  • Các tác vụ không đồng bộ được thiết kế để thực hiện một thao tác ngắn trong nền và cung cấp các kết quả và kết quả trên luồng UI. Các tác vụ Async có các giới hạn như bạn không thể tạo hơn 128 tác vụ AsyncThreadPoolExecutorsẽ chỉ cho phép tối đa 5 tác vụ Async .

  • IntentServicescũng được thiết kế để thực hiện tác vụ nền trong thời gian dài hơn một chút và bạn có thể sử dụng LocalBroadcastđể liên lạc Activity. Nhưng các dịch vụ bị phá hủy sau khi thực hiện nhiệm vụ. Nếu bạn muốn giữ cho nó chạy trong một thời gian dài hơn bạn cần phải làm như thế nào while(true){...}.

Các trường hợp sử dụng có ý nghĩa khác cho Looper Thread:

  • Được sử dụng cho giao tiếp ổ cắm 2 chiều trong đó máy chủ tiếp tục lắng nghe Ổ cắm máy khách và viết lại xác nhận

  • Xử lý bitmap trong nền. Truyền url hình ảnh cho chủ đề Looper và nó sẽ áp dụng các hiệu ứng bộ lọc và lưu trữ nó ở vị trí hợp lý tempe và sau đó phát đường dẫn tạm thời của hình ảnh.


4

Câu trả lời này không liên quan gì đến câu hỏi, nhưng việc sử dụng looper và cách mọi người tạo ra handler và looper trong TẤT CẢ các câu trả lời ở đây là thực tiễn xấu (mặc dù một số giải thích là chính xác), tôi phải đăng bài này:

HandlerThread thread = new HandlerThread(threadName);
thread.start();
Looper looper = thread.getLooper();
Handler myHandler = new Handler(looper);

và để thực hiện đầy đủ


3

Xử lý nhiều mục xuống hoặc tải lên các mục trong Dịch vụ là một ví dụ tốt hơn.

HandlerAsnycTaskthường được sử dụng để truyền bá Sự kiện / Tin nhắn giữa UI (luồng) và luồng công nhân hoặc để trì hoãn các hành động. Vì vậy, chúng có liên quan nhiều hơn đến UI.

Một Loopertác vụ xử lý ( Runnables, Futures ) trong hàng đợi liên quan đến luồng trong nền - ngay cả khi không có tương tác người dùng hoặc giao diện người dùng được hiển thị (ứng dụng tải xuống tệp trong nền trong khi gọi).


1

Looper là gì?

TỪ DOCS

Looper

LooperLớp được sử dụng để chạy một vòng lặp thông báo cho a thread. Chủ đề theo mặc định không có một vòng lặp thông báo liên quan đến chúng; để tạo một cái, hãy gọi prepare()trong luồng là để chạy vòng lặp, và sau đó loop()để nó xử lý các thông báo cho đến khi vòng lặp bị dừng.

  • A Looperlà một vòng lặp xử lý tin nhắn:
  • Một đặc điểm quan trọng của Looper là nó được liên kết với chuỗi trong đó Looper được tạo
  • Lớp Looper duy trì một MessageQueue, trong đó có chứa một thông báo danh sách. Một đặc điểm quan trọng của Looper là nó được liên kết với chuỗi trong đó Looper được tạo.
  • Cái Loopernày được đặt tên như vậy bởi vì nó thực hiện vòng lặp - nhận nhiệm vụ tiếp theo, thực thi nó, sau đó thực hiện tiếp theo và cứ thế. Cái Handlernày được gọi là xử lý vì ai đó không thể phát minh ra một cái tên tốt hơn
  • Android Looperlà một lớp Java trong giao diện người dùng Android cùng với lớp Handler để xử lý các sự kiện UI như nhấp chuột vào nút, vẽ lại màn hình và chuyển đổi định hướng.

Làm thế nào nó hoạt động?

nhập mô tả hình ảnh ở đây

Tạo Looper

Một chủ đề được một LooperMessageQueuebằng cách gọi Looper.prepare()sau khi nó chạy. Looper.prepare()xác định luồng gọi, tạo Looper và MessageQueueđối tượng và liên kết luồng

MẪU MÃ

class MyLooperThread extends Thread {

      public Handler mHandler; 

      public void run() { 

          // preparing a looper on current thread  
          Looper.prepare();

          mHandler = new Handler() { 
              public void handleMessage(Message msg) { 
                 // process incoming messages here
                 // this will run in non-ui/background thread
              } 
          }; 

          Looper.loop();
      } 
  }

Để biết thêm thông tin kiểm tra bên dưới bài


xuất sắc, tôi đã hiểu cơ học. cảm ơn
Serg Burlaka
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.