如何检查Receiver是否已在Android中注册?


Answers:


68

如果您考虑以下线程,则我不确定该API是否直接提供API :

我想知道同样的事情。
就我而言,我有一个BroadcastReceiver实现,Context#unregisterReceiver(BroadcastReceiver)在处理它收到的Intent之后,调用 将自身作为参数传递。
接收者的onReceive(Context, Intent)方法被多次调用的可能性很小,因为它已向多个对象注册IntentFilters,从而有可能IllegalArgumentException被抛出Context#unregisterReceiver(BroadcastReceiver)

就我而言,我可以存储一个私有的同步成员,以便在调用之前进行检查Context#unregisterReceiver(BroadcastReceiver),但是如果API提供了check方法,它将更加干净。


313

没有API函数可以检查接收者是否已注册。解决方法是将您的代码放在一个try catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
真是令人b目结舌... :(
桑德·维尔斯卢伊斯

4
有趣的是,对于registerReceiver(mReceiver,filter1);的BroadcastReceiver调用没有捕获错误。
JPM 2012年

1
@JPM是的。我打算存储接收者的实例,如果没有,请检查注销null。但是,正如您所指出的,我同意try catch。荒谬。

9
不赞成使用Android而不为其创建API。+1为您提供有效的解决方案:)
Denys Vitali

1
有什么更好的?使用此或使用布尔变量作为标志?
DAVIDBALAS1 '16

34

最简单的解决方案

在接收器中:

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

在代码中:

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

广告1

-回复:

这确实不是那么优雅,因为您必须记住在注册后设置isRegistered标志。–隐身犹太教教士

-在接收器中增加了“更加优雅的方式”来注册和设置标志

如果您重新启动设备或您的应用被操作系统杀死,则此操作将无效。– amin 6小时前

@amin-查看已注册接收者的代码中的生命周期(不是清单条目所注册的系统):)


2
这确实是一个优雅的解决方案。FWIW,在Android Studio中,当我尝试扩展BroadcastReceiver时,它抱怨并想要覆盖onReceive。幸运的是,就我而言,我需要扩展ScreenReceiver,它的功能与ceph3us此处描述的完全相同。
MarkJoel60

这确实不是那么优雅,因为您必须记住在注册后设置isRegistered标志。
Stealth Rabbi

是的,尽管您可以从“在代码中”部分删除此行。myReceiver.isRegistered = true;
Stealth Rabbi'2

这不是抽象类吗?扩展BroadcastReceiver要求您实现onReceive方法。
纽约杨

@YorkYang在类的底部添加了信息
ceph3us

27

我正在使用此解决方案

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
哈哈,我觉得它们很方便:)关于格式以及内容开始和结束的地方的简要概述:)我想
每个人都可以-slinden77

1
嗯,根据您的评论进行调查,看起来不错!当然,它搞砸了我的Eclipse工作区,但并不需要太多:)
slinden77 2013年

2
哦,切换到IntelliJ,一旦您习惯了它,Eclipse就会感觉很旧;)从好的方面来说,新的Android Studio只是一个带有一些附加组件的IntelliJ,因此如果您习惯了Intellij,Android Studio将会让您有宾至如归的感觉。
Martin Marconcini

2
@MartínMarconcini很好,最后我被迫切换到IntelliJ。我非常喜欢它,但是我鄙视一个事实,即不可能同时在两个项目中工作。
slinden77 '16

1
欢迎来到黑暗的一面;)我现在打开了三个带有三个不同项目的Android Studio……不确定您的多项目问题是什么,但是我可以向您保证,它可以用于多个项目。:)
Martin Marconcini

22

您有几种选择

  1. 您可以在班级或活动中添加标记。将一个布尔变量放入您的类中,然后查看此标志以了解您是否已注册Receiver。

  2. 创建一个扩展Receiver的类,您可以在其中使用:

    1. 单例模式在您的项目中仅具有此类的一个实例。

    2. 实现用于知道接收方是否已注册的方法。


1
我已经做过同样的事情,但是我的接收者是AppWidgetProvider,我想接收SCREEN_ON_OFF消息-但是当我注销registerReceiver(this)时是onDisabled();-引发异常。
hB0

组合的第一个和第二个选项(接收器类中的一个标记)非常有效
Gaeburider 2014年

你能给我一个代码示例,因为我没有得到你真正正在做的事情吗……将对@chemalarrea有很大帮助
TapanHP


7

您可以轻松完成...。

1)创建一个布尔变量...

private boolean bolBroacastRegistred;

2)注册广播接收器时,将其设置为TRUE

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

3)在onPause()中执行...

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

就这样,现在,您将不会在onPause()上收到更多异常错误消息。

提示1:始终在onPause()中使用unregisterReceiver()而不是在onDestroy()中使用提示2:运行unregisterReceive()时,不要忘记将bolBroadcastRegistred变量设置为FALSE

成功!


6

如果将其放在onDestroy或onStop方法上。我认为,再次创建活动后,就不会再创建MessageReciver了。

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

}

3

我使用Intent来让Broadcast Receiver知道Main Activity线程的Handler实例,并使用Message将消息传递给Main Activity

我已经使用这种机制来检查广播接收器是否已经注册。有时,当您动态注册广播接收器并且不想进行两次注册时,或者在广播接收器正在运行时向用户展示时,需要使用它。

主要活动:

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

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

广播接收器:

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

我个人使用调用unregisterReceiver并吞下异常的方法。我同意这很丑陋,但目前提供了最好的方法。

我提出了一个功能请求,以获取一个布尔方法来检查是否已将接收者注册添加到Android API中。如果您想添加它,请在这里支持:https : //code.google.com/p/android/issues/detail?id=73718


2

我遇到了您的问题,我在应用程序中遇到了同样的问题。我在应用程序中多次调用了registerReceiver()。

解决此问题的简单方法是在“自定义应用程序类”中调用registerReceiver()。这将确保您的广播接收器在整个应用程序生命周期中仅被调用。

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

这就是我的方法,它是ceph3us给出的答案的修改版本,并由slinden77编辑(除其他外,我删除了不需要的方法的返回值):

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

然后在一个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

我把这段代码放在我的父母活动中

列出已注册的接收者=新的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);
}


0

这是我检查广播者是否已经注册的方法,即使您关闭了应用程序(finish())

Firstime运行您的应用程序,首先发送广播,它将返回true / false,这取决于您的广播公司是否仍在运行。

我的广播员

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

我的主要活动

// 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

您可以使用Dagger创建该接收者的参考。

首先提供它:

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

然后将其注入到您需要的地方(使用constructor或字段injection

并将其传递给registerReceiver

也将其放在try/catch块中。



-7

只需检查NullPointerException。如果接收者不存在,则...

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

1
这如何/在哪里抛出NPE?
DustinB 2014年

实际上,如果不成功,它不会引发任何错误。可悲的是。
domenukk

2
事实上,它抛出一个IllegalArgumentException
portfoliobuilder
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.