BroadcastReceiver.onReceive có luôn chạy trong chuỗi giao diện người dùng không?


117

Trong Ứng dụng của mình, tôi tạo một tùy chỉnh BroadcastReceivervà đăng ký nó vào Ngữ cảnh của mình theo cách thủ công qua Context.registerReceiver. Tôi cũng có một AsyncTaskgửi thông báo-Intents qua Context.sendBroadcast. Các ý định được gửi từ một chuỗi nhân viên không phải UI, nhưng có vẻ như BroadcastReceiver.onReceive(nhận được các Ý định đã nói) luôn chạy trong chuỗi UI (điều này tốt cho tôi). Điều này có được đảm bảo hay tôi không nên dựa vào điều đó?

Câu trả lời:


163

BroadcastReceiver.onReceive có luôn chạy trong chuỗi giao diện người dùng không?

Đúng.


9
tài liệu này có ở đâu không
Hannes Struß

15
@hannes: 99,44% thời gian, nếu Android đang gọi mã của bạn, nó nằm trên chuỗi ứng dụng chính. Tất cả các phương pháp vòng đời (ví dụ onCreate(), onReceive()) được gọi trên thread ứng dụng chính. Và, nó được diễn tả trong tài liệu cho onReceive(): goo.gl/8kPuH
CommonsWare

2
ok, tôi chỉ giải thích "thường được gọi trong chuỗi chính" từ tài liệu là "luôn luôn" và hy vọng mọi thứ sẽ không bị hỏng ;-) Cảm ơn!
Hannes Struß

4
@Hannes Struß: Tôi không biết tại sao họ lại bảo vệ ngôn ngữ của mình bằng "bình thường". Tôi không thể nghĩ ra bất kỳ trường hợp nào onReceive()được gọi trên một luồng khác với luồng ứng dụng chính ("Giao diện người dùng").
CommonsWare

31
@CommonsWare: "Tôi không thể nghĩ đến bất kỳ trường hợp nào mà onReceive () được gọi trên một chuỗi không phải là chuỗi ứng dụng chính (" UI ")" - trường hợp này là nếu BroadcastReceiver được đăng ký bằng registerReceiver (BroadcastReceiver, IntentFilter, String, Handler), đối số của trình xử lý không phải là null và tham chiếu đến một trình xử lý được tạo trong một luồng khác với luồng ứng dụng chính.
Jules

76

Vì bạn đăng ký động bộ thu, bạn có thể chỉ định rằng một luồng khác (không phải luồng giao diện người dùng) xử lý onReceive(). Điều này được thực hiện thông qua tham số Handler của registerReceiver () .

Điều đó nói rằng, nếu bạn không chỉ định một Trình xử lý khác, nó sẽ luôn được xử lý trên chuỗi giao diện người dùng.


Đúng. Có vẻ như khả năng bạn thay đổi nó thông qua tham số Handler là lý do tại sao họ "bảo vệ" ngôn ngữ của họ trong tài liệu.
Andrew Mackenzie

64

BroadcastReceiver.onReceive có luôn chạy trong chuỗi giao diện người dùng không?

Thông thường, tất cả phụ thuộc vào cách bạn đăng ký nó.

Nếu bạn đăng ký BroadcastReceiverbằng cách sử dụng:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Nó sẽ chạy trong chuỗi hoạt động chính (hay còn gọi là chuỗi giao diện người dùng) .

Nếu bạn đăng ký của mình BroadcastReceiverbằng cách Handler chạy hợp lệ trên một chuỗi khác :

registerReceiver (BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)

Nó sẽ chạy trong bối cảnh của Handler

Ví dụ:

HandlerThread handlerThread = new HandlerThread("ht");
handlerThread.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
context.registerReceiver(receiver, filter, null, handler); // Will not run on main thread

Thông tin chi tiết tại đây & đây .


3
Sau khi xem xét tùy chọn này một lúc, cuối cùng tôi nhận ra rằng LocalBroadcastManager không hỗ trợ sử dụng trình xử lý tùy chỉnh. Vì vậy, nếu bạn đang sử dụng LBM thay vì ngữ cảnh để đăng ký bộ thu của mình, thì phương pháp này không áp dụng. Thật không may, trong trường hợp đó, có vẻ như lựa chọn duy nhất còn lại của chúng tôi là sử dụng Dịch vụ để chạy ẩn và tránh các ANR mà người nhận kích hoạt sau 10 giây không hoạt động.
gMale

9

Như các câu trả lời trước đã nêu chính xác onReceivesẽ chạy trên luồng mà nó đã đăng ký nếu hương vị của registerReceiver()nó chấp nhận một trình xử lý được gọi - nếu không thì trên luồng chính.

Ngoại trừ trường hợp người nhận được đăng ký với LocalBroadcastManagervà chương trình phát qua sendBroadcastSync- nơi mà nó dường như sẽ chạy trên chuỗi gọisendBroadcastSync.


Tôi không đồng ý với một phần and the broadcast is via sendBroadcastSync. Khi chúng ta sử dụng LocalBroadcastManagerđể đăng ký người nhận, nó phải được gọi bằng luồng chính cho dù sử dụng sendBroadcastSynchay sendBroadcast. Vì vậy, điều quan trọng là sử dụng LocalBroadcastManagerđể đăng ký. Tôi nói đúng chứ?
kidoher

@kidoher: Bạn đã theo dõi các liên kết mã ở đây: stackoverflow.com/q/20820244/281545 ?
Mr_and_Mrs_D

0

CÓ Context.registerReceiver (Bộ thu BroadcastReceiver, Bộ lọc IntentFilter, String broadcastPermission, Bộ lập lịch xử lý)

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.