Làm cách nào để kiểm tra xem Người nhận có được đăng ký trong Android không?


Câu trả lời:


68

Tôi không chắc API cung cấp trực tiếp API, nếu bạn xem xét chủ đề này :

Tôi đã tự hỏi điều tương tự.
Trong trường hợp của tôi, tôi có một BroadcastReceivertriển khai gọi Context#unregisterReceiver(BroadcastReceiver)chính nó là đối số sau khi xử lý Ý định mà nó nhận được.
Có một khả năng nhỏ là onReceive(Context, Intent)phương thức của người nhận được gọi nhiều lần, vì nó được đăng ký với nhiều IntentFilters, tạo ra khả năng IllegalArgumentExceptionbị ném từ đó Context#unregisterReceiver(BroadcastReceiver).

Trong trường hợp của tôi, tôi có thể lưu trữ một thành viên được đồng bộ hóa riêng tư để kiểm tra trước khi gọi Context#unregisterReceiver(BroadcastReceiver), nhưng sẽ sạch hơn nhiều nếu API cung cấp phương thức kiểm tra.


313

Không có chức năng API để kiểm tra nếu người nhận đã đăng ký. Cách giải quyết là đặt mã của bạn vàotry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
đó là một người lập dị ... :(
Sander Versluys

4
Điều thú vị là không bắt lỗi cho cuộc gọi này đến BroadcastReceiver cho registerReceiver (mReceiver, filter1);
JPM

1
@JPM Đúng vậy. Tôi sẽ lưu trữ một phiên bản của máy thu của tôi và kiểm tra để hủy đăng ký nó nếu không null. Nhưng như bạn đã chỉ ra, tôi sẽ làm theo try catch. Nực cười.

9
Downvote cho Android vì không tạo API cho điều đó. +1 cho bạn để cung cấp giải pháp làm việc :)
Denys Vitali

1
Có gì tốt hơn? sử dụng biến này hay sử dụng biến boolean làm cờ?
DAVIDBALAS1

34

giải pháp đơn giản nhất

trong máy thu:

public class MyReceiver extends BroadcastReceiver {   
    public boolean isRegistered;

    /**
    * register receiver
    * @param context - Context
    * @param filter - Intent Filter
    * @return see Context.registerReceiver(BroadcastReceiver,IntentFilter)
    */
    public Intent register(Context context, IntentFilter filter) {
        try {
              // ceph3us note:
              // here I propose to create 
              // a isRegistered(Contex) method 
              // as you can register receiver on different context  
              // so you need to match against the same one :) 
              // example  by storing a list of weak references  
              // see LoadedApk.class - receiver dispatcher 
              // its and ArrayMap there for example 
              return !isRegistered 
                     ? context.registerReceiver(this, filter) 
                     : null;
            } finally {
               isRegistered = true;
            }
    }

    /**
     * unregister received
     * @param context - context
     * @return true if was registered else false
     */
     public boolean unregister(Context context) {
         // additional work match on context before unregister
         // eg store weak ref in register then compare in unregister 
         // if match same instance
         return isRegistered 
                    && unregisterInternal(context);
     }

     private boolean unregisterInternal(Context context) {
         context.unregisterReceiver(this); 
         isRegistered = false;
         return true;
     }

    // rest implementation  here 
    // or make this an abstract class as template :)
    ...
}

trong mã:

MyReceiver myReceiver = new MyReceiver();
myReceiver.register(Context, IntentFilter); // register 
myReceiver.unregister(Context); // unregister 

quảng cáo 1

- trả lời:

Điều này thực sự không thanh lịch bởi vì bạn phải nhớ đặt cờ isRegistered sau khi bạn đăng ký. - Rabbi tàng hình

- Phương thức được thêm vào "cách hợp pháp hơn" trong máy thu để đăng ký và đặt cờ

điều này sẽ không hoạt động nếu bạn khởi động lại thiết bị hoặc nếu ứng dụng của bạn bị hệ điều hành giết chết. - amin 6 giờ trước

@amin - xem thời gian tồn tại của mã (không phải hệ thống được đăng ký bởi mục nhập bảng kê khai) người nhận đã đăng ký :)


2
Đây thực sự là một giải pháp thanh lịch. FWIW, trong Android Studio, khi tôi cố gắng mở rộng BroadcastReceiver, nó phàn nàn và muốn ghi đè onReceive. May mắn thay, trong trường hợp của tôi, tôi cần mở rộng ScreenReceiver, hoạt động chính xác theo cách mà ceph3us mô tả ở đây.
MarkJoel60

Điều này thực sự không thanh lịch bởi vì bạn phải nhớ đặt cờ isRegistered sau khi bạn đăng ký.
Rabbi tàng hình

Có, mặc dù bạn có thể xóa dòng này khỏi phần "trong mã" của mình. myReceiver.isRegistered = true;
Rabbi tàng hình

đây không phải là một lớp trừu tượng? mở rộng BroadcastReceiver yêu cầu bạn thực hiện phương thức onReceive.
York Yang

@YorkYang đã thêm thông tin trong lớp ở phía dưới
ceph3us

27

Tôi đang sử dụng giải pháp này

public class ReceiverManager {

    private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();  
    private static ReceiverManager ref;
    private Context context;

    private ReceiverManager(Context context){
        this.context = context;
    }

    public static synchronized ReceiverManager init(Context context) {      
        if (ref == null) ref = new ReceiverManager(context);
        return ref;
    }

    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter){
        receivers.add(receiver);
        Intent intent = context.registerReceiver(receiver, intentFilter);
        Log.i(getClass().getSimpleName(), "registered receiver: "+receiver+"  with filter: "+intentFilter);
        Log.i(getClass().getSimpleName(), "receiver Intent: "+intent);
        return intent;
    }

    public boolean isReceiverRegistered(BroadcastReceiver receiver){
        boolean registered = receivers.contains(receiver);
        Log.i(getClass().getSimpleName(), "is receiver "+receiver+" registered? "+registered);
        return registered;
    }

    public void unregisterReceiver(BroadcastReceiver receiver){
        if (isReceiverRegistered(receiver)){
            receivers.remove(receiver);
            context.unregisterReceiver(receiver);
            Log.i(getClass().getSimpleName(), "unregistered receiver: "+receiver);
        }
    }
}

2
haha, tôi thấy chúng tiện lợi :) Tổng quan nhanh hơn về định dạng và nơi mọi thứ bắt đầu và kết thúc :) mỗi lần tôi tự đoán
slinden77

1
Mmm, nhìn vào đó theo nhận xét của bạn, nhìn tốt! Tất nhiên, nó làm
hỏng

2
Ồ, chuyển sang IntelliJ, khi bạn đã quen với nó, Eclipse cảm thấy thực sự cũ;) Về mặt tích cực, Android Studio mới chỉ là một IntelliJ với một vài tiện ích bổ sung nên nếu bạn đã quen với Intellij, Android Studio sẽ làm cho bạn cảm thấy như ở nhà
Martin Marconcini

2
@ MartínMarconcini cuối cùng tôi đã buộc phải chuyển sang IntelliJ. Tôi rất thích nó, nhưng tôi khinh thường thực tế là không thể làm việc trong 2 dự án một cách đồng thời.
slinden77

1
Chào mừng bạn đến với mặt tối;) Tôi có ba Android Studio đang mở ngay bây giờ với 3 dự án khác nhau. Không chắc vấn đề nhiều dự án của bạn là gì, nhưng tôi có thể đảm bảo với bạn rằng nó hoạt động với nhiều dự án. :)
Martin Marconcini

22

Bạn có một vài lựa chọn

  1. Bạn có thể đặt một lá cờ vào lớp học hoặc hoạt động của bạn. Đặt một biến boolean vào lớp của bạn và nhìn vào cờ này để biết bạn đã đăng ký Người nhận chưa.

  2. Tạo một lớp mở rộng Người nhận và ở đó bạn có thể sử dụng:

    1. Mẫu đơn chỉ có một thể hiện của lớp này trong dự án của bạn.

    2. Thực hiện các phương pháp để biết nếu người nhận được đăng ký.


1
Tôi đã làm như vậy nhưng người nhận của tôi là AppWidgetProvider và tôi muốn nhận tin nhắn SCREEN_ON_OFF - nhưng onDisables () khi tôi hủy đăng kýReceiver (cái này); - nó ném ngoại lệ.
hB0

kết hợp tùy chọn thứ nhất và thứ hai, một cờ trong lớp người nhận, hoạt động rất tốt
Gaeburider

bạn có thể cho tôi một ví dụ về mã vì tôi không hiểu chính xác bạn đang làm gì ... sẽ giúp ích rất nhiều cho @oolalarrea
TapanHP

11

Bạn phải sử dụng thử / bắt:

try {
    if (receiver!=null) {
        Activity.this.unregisterReceiver(receiver);
    }
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}

7

Bạn có thể làm điều đó dễ dàng ....

1) tạo một biến boolean ...

private boolean bolBroacastRegistred;

2) Khi bạn đăng ký Bộ thu phát sóng, hãy đặt nó thành TRUE

...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....

3) Trong onPause () làm điều đó ...

if (bolBroacastRegistred) {
    this.unregisterReceiver(mReceiver);
    bolBroacastRegistred = false
}

Chỉ có nó và bây giờ, bạn sẽ không nhận được thêm thông báo lỗi ngoại lệ trên onPause ().

Mẹo1: Luôn sử dụng unregisterReceiver () trong onPause () không phải trong onDestroy () Tip2: Đừng quên đặt biến bolBroadcastRegistred thành FALSE khi chạy unregisterReceive ()

Sự thành công!


6

Nếu bạn đặt cái này vào phương thức onDestroy hoặc onStop. Tôi nghĩ rằng khi hoạt động được tạo lại, MessageReciver sẽ không được tạo.

@Override 
public void onDestroy (){
    super.onDestroy();
LocalBroadcastManager.getInstance(context).unregisterReceiver(mMessageReceiver);

}

3

Tôi đã sử dụng Ý định để cho Bộ thu phát sóng biết về phiên bản Trình xử lý của luồng Hoạt động chính và đã sử dụng Tin nhắn để truyền thông điệp đến Hoạt động chính

Tôi đã sử dụng cơ chế như vậy để kiểm tra xem Broadcast Receiver đã được đăng ký hay chưa. Đôi khi, cần thiết khi bạn đăng ký Bộ thu phát sóng một cách linh hoạt và không muốn thực hiện hai lần hoặc bạn trình bày cho người dùng nếu Bộ thu phát sóng đang chạy.

Hoạt động chủ yêu:

public class Example extends Activity {

private BroadCastReceiver_example br_exemple;

final Messenger mMessenger = new Messenger(new IncomingHandler());

private boolean running = false;

static class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        running = false;    
        switch (msg.what) {
        case BroadCastReceiver_example.ALIVE:
    running = true;
            ....
            break;
        default:

            super.handleMessage(msg);
        }

    }
    }

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter();
        filter.addAction("pl.example.CHECK_RECEIVER");

        br_exemple = new BroadCastReceiver_example();
        getApplicationContext().registerReceiver(br_exemple , filter); //register the Receiver
    }

// call it whenever you want to check if Broadcast Receiver is running.

private void check_broadcastRunning() {    
        /**
        * checkBroadcastHandler - the handler will start runnable which will check if Broadcast Receiver is running
        */
        Handler checkBroadcastHandler = null;

        /**
        * checkBroadcastRunnable - the runnable which will check if Broadcast Receiver is running
        */
        Runnable checkBroadcastRunnable = null;

        Intent checkBroadCastState = new Intent();
        checkBroadCastState .setAction("pl.example.CHECK_RECEIVER");
        checkBroadCastState .putExtra("mainView", mMessenger);
        this.sendBroadcast(checkBroadCastState );
        Log.d(TAG,"check if broadcast is running");

        checkBroadcastHandler = new Handler();
        checkBroadcastRunnable = new Runnable(){    

            public void run(){
                if (running == true) {
                    Log.d(TAG,"broadcast is running");
                }
                else {
                    Log.d(TAG,"broadcast is not running");
                }
            }
        };
        checkBroadcastHandler.postDelayed(checkBroadcastRunnable,100);
        return;
    }

.............
}

Phát sóng thu:

public class BroadCastReceiver_example extends BroadcastReceiver {


public static final int ALIVE = 1;
@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Bundle extras = intent.getExtras();
    String action = intent.getAction();
    if (action.equals("pl.example.CHECK_RECEIVER")) {
        Log.d(TAG, "Received broadcast live checker");
        Messenger mainAppMessanger = (Messenger) extras.get("mainView");
        try {
            mainAppMessanger.send(Message.obtain(null, ALIVE));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    .........

}

}

3

Cá nhân tôi sử dụng phương pháp gọi unregisterReceiver và nuốt ngoại lệ nếu nó bị ném. Tôi đồng ý điều này là xấu nhưng phương pháp tốt nhất hiện đang được cung cấp.

Tôi đã đưa ra một yêu cầu tính năng để có được phương thức boolean để kiểm tra xem người nhận có được đăng ký thêm vào API Android hay không. Vui lòng hỗ trợ tại đây nếu bạn muốn xem nó được thêm vào: https://code.google.com.vn/p/android/issues/detail?id=73718


2

Tôi nhận được vấn đề của bạn, tôi đã đối mặt với cùng một vấn đề trong Ứng dụng của tôi. Tôi đã gọi registerReceiver () nhiều lần trong ứng dụng.

Một giải pháp đơn giản cho vấn đề này là gọi registerReceiver () trong Lớp ứng dụng tùy chỉnh của bạn. Điều này sẽ đảm bảo rằng bộ thu phát của bạn sẽ chỉ được gọi là một trong toàn bộ vòng đời Ứng dụng của bạn.

public class YourApplication extends Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        //register your Broadcast receiver here
        IntentFilter intentFilter = new IntentFilter("MANUAL_BROADCAST_RECIEVER");
        registerReceiver(new BroadcastReciever(), intentFilter);

    }
}

1

Đây là cách tôi đã thực hiện, đây là phiên bản sửa đổi của câu trả lời được đưa ra bởi ceph3us và được chỉnh sửa bởi slinden77 (trong số những thứ khác tôi đã xóa các giá trị trả về của các phương thức mà tôi không cần):

public class MyBroadcastReceiver extends BroadcastReceiver{
    private boolean isRegistered; 

    public void register(final Context context) {
        if (!isRegistered){
            Log.d(this.toString(), " going to register this broadcast receiver");
            context.registerReceiver(this, new IntentFilter("MY_ACTION"));
            isRegistered = true;
        }
    }
    public void unregister(final Context context) {
        if (isRegistered) {            
            Log.d(this.toString(), " going to unregister this broadcast receiver");
            context.unregisterReceiver(this);
            isRegistered = false;
        }
    }
    @Override
    public void onReceive(final Context context, final Intent intent) {        
        switch (getResultCode()){
        //DO STUFF
        }        
    }        
}

Sau đó, trên một lớp Activity:

public class MyFragmentActivity extends SingleFragmentActivity{
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        registerBroacastReceiver();       
    }

    @Override
    protected Fragment createFragment(){
        return new MyFragment();
    }

    //This method is called by the fragment which is started by this activity, 
    //when the Fragment is done, we also register the receiver here (if required)
    @Override
    public void receiveDataFromFragment(MyData data) {
        registerBroacastReceiver();
        //Do some stuff                
    }

    @Override
    protected void onStop(){        
        unregisterBroacastReceiver();
        super.onStop();
    }

    void registerBroacastReceiver(){
        if (myBroadcastReceiver == null)
            myBroadcastReceiver = new MyBroadcastReceiver();
        myBroadcastReceiver.register(this.getApplicationContext());
    }

    void unregisterReceiver(){
        if (MyBroadcastReceiver != null)
            myBroadcastReceiver.unregister(this.getApplicationContext());
    }
}

1

tôi đặt mã này vào hoạt động của cha mẹ tôi

Danh sách đã đăng kýReceivers = new ArrayList <> ();

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    registeredReceivers.add(System.identityHashCode(receiver));
    return super.registerReceiver(receiver, filter);
}

@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
    if(registeredReceivers.contains(System.identityHashCode(receiver)))
    super.unregisterReceiver(receiver);
}

1

Đối với tôi sau đây làm việc:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}

0

Đây là những gì tôi đã làm để kiểm tra xem Broadcaster đã được đăng ký chưa, ngay cả khi bạn đóng ứng dụng của bạn (finish ())

Lần đầu tiên chạy ứng dụng của bạn, hãy gửi phát trước, nó sẽ trả về true / false tùy thuộc vào việc đài phát của bạn có còn chạy hay không.

Phát thanh viên của tôi

public class NotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getExtras() != null && intent.getStringExtra("test") != null){
            Log.d("onReceive","test");
            return;
        }
    }
}

Chính của tôi

// init Broadcaster
private NotificationReceiver nr = new NotificationReceiver();


Intent msgrcv = new Intent("Msg");
msgrcv.putExtra("test", "testing");
boolean isRegistered = LocalBroadcastManager.getInstance(this).sendBroadcast(msgrcv);

if(!isRegistered){
    Toast.makeText(this,"Starting Notification Receiver...",Toast.LENGTH_LONG).show();
    LocalBroadcastManager.getInstance(this).registerReceiver(nr,new IntentFilter("Msg"));
}

0

Bạn có thể sử dụng Dagger để tạo một tham chiếu của người nhận đó.

Đầu tiên cung cấp nó:

@Provides
@YourScope
fun providesReceiver(): NotificationReceiver{
    return NotificationReceiver()
}

Sau đó tiêm vào nơi bạn cần (sử dụng constructorhoặc trường injection)

và chỉ cần chuyển nó đến registerReceiver .

Cũng đặt nó trong try/catchkhối quá.


-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}

1
Phát sóng theo thứ tự là một điều hoàn toàn khác hãy xem liên kết này
Vivek Barai

-7

Chỉ cần kiểm tra NullPulumException. Nếu máy thu không tồn tại, thì ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}

1
Làm thế nào / nơi này ném NPE?
DustinB

Nó thực sự không ném bất kỳ lỗi nào khi nó không thành công. Thật đáng buồn.
domenukk

2
Trên thực tế, nó ném một IllegalArgumentException
portfoliobuilder
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.