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

Мне нужно проверить, зарегистрирован ли мой зарегистрированный получатель, если нет, как мне проверить это какими-либо методами?


person Mikey    schedule 21.04.2010    source источник
comment
code.google.com/p/android/issues/detail?id= 73718   -  person Shirish Herwade    schedule 11.08.2016


Ответы (18)



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

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
person Daniel    schedule 25.08.2010
comment
Забавно то, что при этом вызове BroadcastReceiver для registerReceiver (mReceiver, filter1) не обнаруживается ошибка; - person JPM; 02.03.2012
comment
@JPM Да, это так. Я собирался сохранить экземпляр своего приемника и проверить, чтобы отменить его регистрацию, если он не null. Но, как вы отметили, я собираюсь использовать try catch. Нелепый. - person ; 28.11.2012
comment
Проголосуйте против Android за то, что не создали для этого API. +1 вам за предоставленное рабочее решение :) - person Denys Vitali; 23.03.2016
comment
Что лучше? используя это или используя логическую переменную в качестве флага? - person DAVIDBALAS1; 19.08.2016
comment
@ DAVIDBALAS1 Я думаю, это может зависеть от варианта использования. Я решил использовать логическое значение, потому что эта переменная снова мне пригодится. - person AlbertMarkovski; 30.09.2016
comment
Я буду использовать это вместо логической переменной в качестве флага, потому что я не хочу делать еще одну переменную в своем классе и поддерживать состояние флага. Особенно если мой класс уже большой - person HendraWD; 20.10.2016
comment
Я буду использовать это вместо логической переменной в качестве флага, потому что, если регистрация по-прежнему висит по какой-либо причине и для флага еще не установлено значение true, то отмена регистрации все равно вызовет исключение - person ocramot; 10.05.2018
comment
Я опубликовал аналогичное сообщение о запросе состояния MediaCodec. Убедитесь, что это интересно: stackoverflow.com/q/51780322/1562087 - person KenIchi; 24.08.2018

простейшее решение

в приемнике:

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 - увидеть время жизни зарегистрированного получателя в коде (не зарегистрированном системой в манифесте) :)

person ceph3us    schedule 24.04.2015
comment
Это действительно элегантное решение. FWIW в Android Studio, когда я пытаюсь расширить BroadcastReceiver, он жалуется и хочет переопределить onReceive. К счастью, в моем случае мне понадобилось расширить ScreenReceiver, который работает точно так, как здесь описывает ceph3us. - person MarkJoel60; 24.10.2015
comment
Это действительно не так элегантно, потому что вы должны не забыть установить флаг isRegistered после регистрации. - person Stealth Rabbi; 15.02.2016
comment
Да, хотя вы можете удалить эту строку из своего раздела кода. myReceiver.isRegistered = true; - person Stealth Rabbi; 16.02.2016
comment
Разве это не должен быть абстрактный класс? Расширение BroadcastReceiver требует, чтобы вы реализовали метод onReceive. - person York Yang; 09.08.2017
comment
@YorkYang добавил информацию в класс внизу - person ceph3us; 09.08.2017
comment
это не сработает, если вы перезагрузите устройство или ваше приложение было убито ОС. - person Amin Pinjari; 30.04.2019

Я использую это решение

public class ReceiverManager {
    private WeakReference<Context> cReference;
    private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();
    private static ReceiverManager ref;

    private ReceiverManager(Context context) {
        cReference = new WeakReference<>(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 = cReference.get().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);
            cReference.get().unregisterReceiver(receiver);
            Log.i(getClass().getSimpleName(), "unregistered receiver: " + receiver);
        }
    }
}

person slinden77    schedule 13.04.2013
comment
ха-ха, они мне удобны :) Более быстрый обзор формата и того, где все начинается и где заканчивается :) Я думаю, каждый по-своему - person slinden77; 25.05.2013
comment
ммм, глядя на это в соответствии с вашим комментарием, хорошо выглядеть! Конечно, это испортило мою рабочую область Eclipse, но для этого не так много нужно :) - person slinden77; 28.05.2013
comment
О, переключитесь на IntelliJ, как только вы привыкнете к нему, Eclipse станет действительно старым;) С другой стороны, новая Android Studio - это просто IntelliJ с несколькими надстройками, поэтому, если вы привыкли к Intellij, Android Studio будет заставить вас чувствовать себя как дома. - person Martin Marconcini; 28.05.2013
comment
@ MartínMarconcini Ну, наконец, я был вынужден перейти на IntelliJ. Мне это очень нравится, но я с презрением отношусь к тому факту, что невозможно работать в двух проектах одновременно. - person slinden77; 16.08.2016
comment
Добро пожаловать на темную сторону;) У меня сейчас открыто три Android Studio с 3 разными проектами ... не знаю, в чем заключается ваша проблема с несколькими проектами, но могу вас заверить, что он работает с несколькими проектами. :) - person Martin Marconcini; 16.08.2016
comment
вниз из-за утечки контекста (вы слышали о слабых ссылках)? - person ceph3us; 09.08.2017
comment
Это из класса TelephonyManager? @ slinden77 - person exploitr; 27.06.2018
comment
Кроме того, ваш код подталкивает к утечкам памяти. Не пытайтесь размещать классы контекста в статических полях. Используйте WeakReference. В любом случае +1 - person exploitr; 27.06.2018
comment
Я внес изменения, чтобы удерживать контент в WeakReference. - person Steve Kamau; 14.07.2020

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

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

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

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

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

person chemalarrea    schedule 14.02.2012
comment
Я сделал то же самое, но мой получатель - это AppWidgetProvider, и я хочу получать сообщения SCREEN_ON_OFF, но onDisabled (), когда я отменяю регистрациюReceiver (this); - выдает исключение. - person hB0; 12.07.2013
comment
совмещенный первый и второй вариант, флаг в классе приемника, отлично работает - person Gaeburider; 05.06.2014
comment
Можете ли вы привести мне пример кода, так как я не понимаю, что именно вы делаете ... Было бы здорово помочь @chemalarrea - person TapanHP; 18.01.2017

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

try {
    if (receiver!=null) {
        Activity.this.unregisterReceiver(receiver);
    }
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}
person Mohsen mokhtari    schedule 15.03.2017

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

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

private boolean bolBroacastRegistred;

2) Когда вы регистрируете свой широковещательный приемник, установите для него значение ИСТИНА.

...
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 ().

Успех!

person Biruel Rick    schedule 16.11.2014

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

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

}
person eloirobe    schedule 06.06.2013

Я использовал намерение, чтобы широковещательный приемник знал об экземпляре обработчика основного потока активности, и использовал сообщение, чтобы передать сообщение в основное действие.

Я использовал такой механизм, чтобы проверить, зарегистрирован ли 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();
        }
    }
    .........

}

}
person jarek    schedule 13.10.2013

Лично я использую метод вызова unregisterReceiver и проглатывания исключения, если оно сгенерировано. Я согласен, что это уродливый, но лучший из имеющихся на данный момент методов.

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

person ojf    schedule 17.07.2014

Я понял вашу проблему, я столкнулся с той же проблемой в своем приложении. Я несколько раз звонил 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);

    }
}
person Sameer Ranjan    schedule 21.03.2018

Для меня сработало следующее:

if (receiver.isOrderedBroadcast()) {
   requireContext().unregisterReceiver(receiver);
}
person Benjamin Corben    schedule 07.02.2020

Вот как я это сделал, это измененная версия ответа, данного 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());
    }
}
person Víctor Gil    schedule 18.12.2016

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

Список зарегистрированных получателей = новый 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);
}
person darkwater84    schedule 31.08.2017

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

При первом запуске вашего приложения отправьте сначала широковещательную рассылку, она вернет истину / ложь, в зависимости от того, работает ваш вещатель или нет.

Мой телеведущий

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"));
}
person janbee    schedule 07.07.2016

Вы можете использовать Dagger, чтобы создать ссылку на этого получателя.

Сначала предоставьте это:

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

Затем введите его туда, где вам нужно (используя constructor или поле injection)

и просто передайте его registerReceiver.

Также поместите его в блок try/catch.

person Mahdi-Malv    schedule 24.12.2018

Просто проверьте NullPointerException. Если ресивер не существует, то ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
person Kasra    schedule 25.06.2014
comment
Как / где это бросает NPE? - person DustinB; 27.06.2014
comment
На самом деле, он не выдает никаких ошибок, когда он неудачен. Грустно. - person domenukk; 09.10.2014
comment
На самом деле это вызывает исключение IllegalArgumentException. - person portfoliobuilder; 22.07.2015

person    schedule
comment
Заказная трансляция - совсем другое дело, взгляните на эту ссылку - person Vivek Barai; 14.11.2017