Android: Khi nào tôi nên sử dụng Trình xử lý () và khi nào tôi nên sử dụng Chủ đề?


129

Khi tôi cần một cái gì đó để chạy không đồng bộ , chẳng hạn như một tác vụ chạy dài hoặc logic sử dụng mạng hoặc vì bất kỳ lý do gì, Bắt đầu một Chủ đề mới và chạy nó hoạt động tốt. Tạo một Handler và chạy nó cũng hoạt động. Có gì khác biệt? Khi nào tôi nên sử dụng mỗi một? Những lợi thế / lý do để sử dụng a Handlervà không phải là Threadgì?

Tái bút - Vì câu hỏi này, hãy bỏ qua AsyncTask. - Handler().postDelayedtrường hợp sử dụng là rõ ràng đối với tôi, vì câu hỏi này, giả sử tôi cần nhiệm vụ để bắt đầu ngay lập tức.


Trong tình huống của bạn chỉ cần đi thẳng và sử dụng một Chủ đề mới, đề xuất tiếp theo của tôi sẽ là AsyncTask nhưng đó không phải là điều bạn muốn rõ ràng. Trình xử lý chủ yếu được sử dụng nếu bạn muốn thêm một độ trễ hoặc một số loại tùy chỉnh khác vào một runnable.
kabuto178

1
@ kabuto178 tốt, có những lợi ích khác của trình xử lý đáng nói mà bạn bỏ qua. Chẳng hạn như, có thể tương tác với luồng UI từ một luồng riêng biệt ..
tony9099

Câu trả lời:


168

Nếu bất cứ điều gì bạn đang làm là "nặng", bạn nên thực hiện nó trong một Chủ đề. Nếu bạn không khởi động nó một cách rõ ràng trong luồng của chính nó, thì nó sẽ chạy trên luồng chính (UI) có thể đáng chú ý là giao diện bị giật hoặc chậm bởi người dùng của bạn.

Thật thú vị khi bạn đang sử dụng một luồng, thường rất hữu ích khi sử dụng Trình xử lý như một phương tiện giao tiếp giữa luồng công việc mà bạn đang bắt đầu và luồng chính.

Một tương tác Thread / Handler điển hình có thể trông giống như thế này:

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

Tuy nhiên, nói chung, việc mang về nhà là bạn nên sử dụng một Chủ đề bất cứ khi nào bạn đang thực hiện một số công việc có thể chạy lâu hoặc rất chuyên sâu (ví dụ như bất kỳ mạng nào, tệp IO, arithmatic nặng, v.v.).


Cảm ơn bạn đã trả lời nhanh chóng và thời gian đầu tư (và tốc độ trả lời của bạn !!)! Vì vậy, hãy để tôi xem nếu tôi có được điều này: Handler được thiết kế để tạo điều kiện cho việc liên lạc không chặn giữa các luồng công nhân và luồng UI?
JRun

3
@JRun Đó là một trong những cách sử dụng có. Kiểm tra mô tả Handler trong tài liệu java để biết một số thông tin tuyệt vời về nó. Bao gồm một mục đích sử dụng khác (để lên lịch các tin nhắn và runnables sẽ được thực thi như một số điểm trong tương lai).
FoamyGuy

giải thích độc đáo @FoamyGuy!
tony9099

Xin chào, có đảm bảo rằng nó updateUI()sẽ chạy sau onCreateView(sau khi lượt xem mới được tải) không?
Zyoo

1
Tại sao vậy message.what()? Nó sẽ không phải là if(msg == 0){? Cám ơn rất nhiều! :)
Ruchir Baronia

64

Handler và Thread thực sự là 2 thứ khác nhau.

Một luồng phải được tạo để thực hiện các công việc chạy dài.

Handler là đối tượng rất thuận tiện để giao tiếp giữa 2 luồng (ví dụ: luồng nền cần cập nhật UI. Bạn có thể sử dụng Handler để đăng một số Runnable từ luồng nền của bạn lên luồng UI).

Vì vậy, bạn không có sự lựa chọn giữa Handler hoặc Thread. Sử dụng một chủ đề để làm công việc nặng! (bạn có thể sử dụng Trình xử lý nếu luồng nền của bạn sẽ kích hoạt một số công việc được thực hiện trong luồng khác - hầu hết thời gian của luồng UI)


Cảm ơn bạn đã trả lời nhanh chóng và thời gian đầu tư (và tốc độ trả lời của bạn !!)!
JRun

28

HandlerThreadlà hai điều khác nhau, nhưng chúng không mâu thuẫn với nhau. Bạn có thể có một Handlervà một Threadcùng một lúc và thực sự mỗi cái Handlerphải được chạy trong mộtThread .

Để biết thêm chi tiết, bạn có thể muốn xem bài viết này .

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


19

A Handlerchạy trên cùng Thread, mộtThread chạy trên một chủ đề khác nhau.

Sử dụng Trình xử lý nếu bạn cần chạy một cái gì đó trên cùng một chuỗi , thường là phần tử GUI hoặc một cái gì đó tương tự.

Sử dụng một Chủ đề nếu bạn muốn giữ cho chủ đề chính miễn phí để làm những việc khác . Sử dụng điều này cho bất cứ điều gì cần một lượng thời gian đáng kể.


6
Tại sao tôi nên sử dụng một trình xử lý nếu tôi muốn chạy một cái gì đó trên cùng một chủ đề? mục đích của phương pháp mHandler.post (...) là gì?
Elias

1
Elias, trong trường hợp như vậy, bạn có thể sử dụng trình xử lý nếu bạn muốn một tác vụ nhất định chạy sau một khoảng thời gian nhất định hoặc lặp lại một tác vụ sau mỗi khoảng thời gian X. Nếu bạn không muốn sử dụng những thứ này, bạn đã đúng. nó là không xứng đáng để sử dụng một xử lý. bạn chỉ có thể thực hiện các thao tác GUI ngay tại đó và sau đó, dù sao bạn cũng đang ở trong giao diện người dùng, bởi vì trình xử lý chạy trên luồng mà nó được tạo.
tony9099

14

Trình xử lý là cách giao tiếp tốt nhất giữa nền và luồng UI. Nói chung Trình xử lý được liên kết với tin nhắn Hàng đợi của một Chủ đề và chúng được sử dụng để gửi tin nhắn và có thể chạy đến Tin nhắn.

SỬ DỤNG:

Chủ đề: Để thực hiện các tác vụ trong luồng (nền) so với luồng UI. (giúp bỏ chặn luồng UI)

Xử lý Được sử dụng để giao tiếp giữa giao diện người dùng và chủ đề nền.

Có một cái nhìn tại đây bài viết này


4

Nếu bạn cần cập nhật giao diện người dùng từ một Chủ đề mới, bạn cần đồng bộ hóa với chủ đề giao diện người dùng.

Bạn có thể sử dụng lớp android.os.Handler hoặc lớp AsyncT task cho việc này.

Lớp Handler có thể cập nhật giao diện người dùng. Handler cung cấp các phương thức để nhận các thể hiện của lớp Message hoặc Runnable.

Bạn có thể gửi tin nhắn thông qua phương thức sendMessage (Thông điệp tin nhắn) hoặc thông qua phương thức sendEmptyMessage ().

... thêm thông tin ở đây về các chủ đề, v.v. (bao gồm các phần mềm cho các cơ chế phân luồng và đồng bộ hóa khác nhau và khi nào nên sử dụng cái gì)


Cảm ơn đã dành thời gian để trả lời câu hỏi của tôi. Tôi yêu blog của Lars Vogel, nó rất sâu sắc và dễ theo dõi. Cảm ơn!
JRun

2

Những lợi thế / lý do để sử dụng Handler và không phải là Thread là gì?

Trình xử cho phép bạn gửi và xử lý Tin nhắn và Runnablecác đối tượng được liên kết với một chuỗi MessageQueue. Mỗi Handlerphiên bản được liên kết với một luồng và hàng đợi tin nhắn của luồng đó.

Khi bạn tạo một cái mới Handler , nó bị ràng buộc với hàng đợi luồng / tin nhắn của luồng đang tạo nó - từ thời điểm đó, nó sẽ gửi tin nhắn và runnable đến hàng đợi tin nhắn đó và thực hiện chúng khi chúng ra khỏi hàng đợi tin nhắn .

Có hai cách sử dụng chính cho Handler:

  1. Để lên lịch tin nhắn và Runnables sẽ được thực thi như một số điểm trong tương lai
  2. Để enqueue một hành động được thực hiện trên một sợi khác với của riêng bạn.

Nếu bạn sử dụng các luồng java, bạn phải tự xử lý một số thứ - đồng bộ hóa với luồng chính, hủy bỏ một luồng, v.v.

Chủ đề duy nhất này không tạo ra một nhóm chủ đề trừ khi bạn sử dụng ThreadPoolExecutorhoặcExecutorService API.

(Lấy truy vấn này từ nhận xét của bạn về câu trả lời của Blackbelt)

Tại sao không sử dụng Executor? và ngay cả khi tôi đã muốn sử dụng Handler để làm điều đó, làm thế nào?

Tài liệu tham khảo : Bài viết hiệu suất chủ đề

Có một số loại công việc nhất định có thể được giảm xuống thành các nhiệm vụ phân tán, song song cao. Với khối lượng lớn các gói công việc, điều này tạo ra AsyncTaskHandlerThreadkhông phải là các lớp thích hợp. Bản chất đơn luồng của AsyncTasksẽ biến tất cả các công việc phân luồng thành một hệ thống tuyến tính. Sử dụngHandlerThreadMặt khác, lớp sẽ yêu cầu lập trình viên quản lý thủ công cân bằng tải giữa một nhóm các luồng.

ThreadPoolExecutor là một lớp trợ giúp để làm cho quá trình này dễ dàng hơn. Lớp này quản lý việc tạo ra một nhóm các luồng, đặt mức độ ưu tiên của chúng và quản lý cách phân phối công việc giữa các luồng đó. Khi khối lượng công việc tăng hoặc giảm, lớp sẽ tăng hoặc phá hủy nhiều luồng hơn để điều chỉnh theo khối lượng công việc.

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

Bạn có thể tham khảo bài viết hướng dẫn dành cho nhà phát triển này trên creat-threadpool để biết thêm chi tiết.

Hãy xem bài đăng này để sử dụng Handlerđể chạy nhiều phiên bản Runnable. Trong trường hợp này, tất cả các Runnabletác vụ sẽ chạy trong một Chủ đề duy nhất.

Android: Toast trong một chủ đề


1

Handlercó thể được sử dụng cùng với Threadđể tạo cơ chế Xếp hàng. Bạn có thể sử dụng handlerđể đăng một cái gì đó trênThread Looper


Cảm ơn đã dành thời gian để trả lời câu hỏi của tôi. Tại sao không sử dụng Executor? và ngay cả khi tôi đã muốn sử dụng Handler để làm điều đó, làm thế nào?
JRun

chấp hành là một chút khác nhau. Để sử dụng nó, bạn phải mở rộng luồng và trong khi chạy, hãy gọi hàm static.metohd.of của lớp Looper. sau khi bạn gọi vòng lặp phương thức tĩnh, một hàng đợi được tạo và bạn có thể sử dụng lệnh handlerbin để chuyển tiếp yêu cầu và nhận lại kết quả
Blackbelt
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.