Как проверить, зарегистрирован ли Receiver в Android?


Ответы:


68

Я не уверен, что API предоставляет напрямую API, если вы рассматриваете эту тему :

Я думал о том же самом.
В моем случае у меня есть BroadcastReceiverреализация, которая вызывает Context#unregisterReceiver(BroadcastReceiver)передачу себя в качестве аргумента после обработки полученного намерения.
Существует небольшая вероятность того, что метод получателя onReceive(Context, Intent)вызывается более одного раза, поскольку он зарегистрирован с помощью множественного числа IntentFilters, что создает возможность для IllegalArgumentExceptionвыброса из него Context#unregisterReceiver(BroadcastReceiver).

В моем случае я могу сохранить частный синхронизированный член для проверки перед вызовом Context#unregisterReceiver(BroadcastReceiver), но было бы намного чище, если бы API предоставил метод проверки.


313

Нет функции API, чтобы проверить, зарегистрирован ли получатель. Обходной путь должен поместить ваш код вtry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
это облом ... :(
Сандер Верслуйс

4
Забавно, что не ловит ошибку при этом вызове BroadcastReceiver для registerReceiver (mReceiver, filter1);
JPM

1
@JPM Да, это так. Я собирался сохранить экземпляр моего приемника и проверить, чтобы отменить его регистрацию, если это не так null. Но, как вы указали, я иду с try catch. Смешной.

9
Downvote для Android, чтобы не создавать API для этого. +1 вам за предоставление рабочего решения :)
Денис Виталий

1
Что лучше? используя это или используя логическую переменную в качестве флага?
ДАВИДБАЛАС1

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 после регистрации. - Стелс Раввин

- «более элегантный способ» добавлен метод в приемнике для регистрации и установки флага

это не сработает, если вы перезапустите устройство или ваше приложение будет убито ОС. - амин 6 часов назад

@amin - видеть время жизни зарегистрированного получателя в коде (а не в системе, зарегистрированной в декларации) :)


2
Это действительно элегантное решение. FWIW, в Android Studio, когда я пытаюсь расширить BroadcastReceiver, он жалуется и хочет переопределить onReceive. К счастью, в моем случае мне потребовалось расширить ScreenReceiver, который работает именно так, как описано здесь ceph3us.
MarkJoel60

Это действительно не так уж и элегантно, потому что вы должны помнить, чтобы установить флаг isRegistered после регистрации.
Раввин Стелс

Да, хотя вы можете удалить эту строку из раздела «в коде». myReceiver.isRegistered = true;
Раввин Стелс

не должен ли это быть абстрактный класс? Расширение 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
ха-ха, я нахожу их удобными :) Более быстрый обзор формата и того, где все начинается и заканчивается :) Я думаю,
каждый

1
ммм, глядя на это согласно вашему комментарию, выглядит хорошо! Конечно, это испортило мое рабочее пространство Eclipse, но для этого не нужно много :)
slinden77

2
О, переключитесь на IntelliJ, как только вы к этому привыкнете, Eclipse чувствует себя очень старым;) С другой стороны, новая Android Studio - это просто IntelliJ с несколькими надстройками, поэтому, если вы привыкли к Intellij, Android Studio будет заставить вас чувствовать себя как дома.
Мартин Маркончини

2
@ MartínMarconcini наконец-то я был вынужден перейти на IntelliJ. Мне это очень нравится, но я презираю тот факт, что невозможно одновременно работать в двух проектах.
slinden77

1
Добро пожаловать на темную сторону;) У меня сейчас открыто три Android Studio с 3-мя разными проектами… не знаю, в чем заключается проблема с несколькими проектами, но я могу заверить вас, что она работает с несколькими проектами. :)
Мартин Маркончини

22

У вас есть несколько вариантов

  1. Вы можете поместить флаг в свой класс или деятельность. Поместите в ваш класс логическую переменную и посмотрите на этот флаг, чтобы узнать, зарегистрирован ли у вас Receiver.

  2. Создайте класс, который расширяет Receiver и там вы можете использовать:

    1. У шаблона Singleton только один экземпляр этого класса в вашем проекте.

    2. Реализуйте методы, чтобы узнать, зарегистрирован ли получатель.


1
Я сделал то же самое, но мой получатель - AppWidgetProvider, и я хочу получать сообщения SCREEN_ON_OFF - но onDisabled (), когда я отменяю регистрацию Receiver (this); - это исключение.
hB0

Совмещенный первый и второй вариант, флаг в классе приемника,
отлично

Можете
ли

11

Вы должны использовать try / catch:

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

7

Вы можете сделать это легко ....

1) создать логическую переменную ...

private boolean bolBroacastRegistred;

2) Когда вы регистрируете свой Broadcast Receiver, установите его в TRUE

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

3) В onPause () сделай это ...

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

Просто так, и теперь вы не будете получать больше сообщений об ошибках исключения onPause ().

Совет 1: всегда используйте unregisterReceiver () в onPause (), а не в onDestroy (). Совет 2: не забывайте устанавливать переменную bolBroadcastRegistred в FALSE при запуске unregisterReceive ()

Успех!


6

Если вы положите это на метод onDestroy или onStop. Я думаю, что когда действие было создано снова, MessageReciver не был создан.

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

}

3

Я использовал Intent, чтобы сообщить Broadcast Receiver об экземпляре Handler основного потока Activity, и использовал Message, чтобы передать сообщение в Main Activity

Я использовал такой механизм, чтобы проверить, зарегистрирован ли Broadcast Receiver или нет. Иногда это необходимо, когда вы регистрируете свой Broadcast Receiver динамически и не хотите делать это дважды, или вы представляете его пользователю, если работает Broadcast Receiver.

Основное занятие:

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 и проглатывания исключения, если оно выдается. Я согласен, что это уродливо, но лучший метод в настоящее время предоставляется.

Я поднял запрос функции, чтобы получить логический метод, чтобы проверить, зарегистрирован ли получатель, добавленный к API Android. Пожалуйста, поддержите его здесь, если вы хотите, чтобы он был добавлен: https://code.google.com/p/android/issues/detail?id=73718


2

Я понял вашу проблему, я столкнулся с той же проблемой в моем приложении. Я вызывал registerReceiver () несколько раз в приложении.

Простое решение этой проблемы - вызвать registerReceiver () в вашем классе пользовательских приложений. Это гарантирует, что ваш приемник Broadcast будет вызываться только один на протяжении всего жизненного цикла приложения.

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

я поместил этот код в мою родительскую деятельность

List selectedReceivers = 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);
}


0

Вот что я сделал, чтобы проверить, зарегистрирован ли Broadcaster, даже если вы закрываете свое приложение (finish ())

Во время запуска вашего приложения отправьте трансляцию первым, и она вернет значение 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

На самом деле он не выдает никаких ошибок, когда это не удается. К сожалению.
Доменюк

2
На самом деле, это создает исключение IllegalArgumentException
портфель
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.