Como verificar se o Receiver está registrado no Android?

Respostas:

68

Não tenho certeza de que a API forneça diretamente uma API, se você considerar este segmento :

Eu estava pensando a mesma coisa.
No meu caso, eu tenho uma BroadcastReceiverimplementação que chama Context#unregisterReceiver(BroadcastReceiver)passando-se como o argumento depois de manipular o Intent que ele recebe.
Há uma pequena chance de que o onReceive(Context, Intent)método do receptor seja chamado mais de uma vez, uma vez que é registrado com múltiplos IntentFilters, criando o potencial para IllegalArgumentExceptionser jogado Context#unregisterReceiver(BroadcastReceiver).

No meu caso, posso armazenar um membro sincronizado privado para verificar antes de ligar Context#unregisterReceiver(BroadcastReceiver), mas seria muito mais limpo se a API fornecesse um método de verificação.

VonC
fonte
313

Não há função de API para verificar se um receptor está registrado. A solução alternativa é colocar seu código em umtry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
Daniel Velkov
fonte
83
Isso é uma chatice ... :(
Sander Versluys
4
O engraçado é que não capta o erro desta chamada para BroadcastReceiver for registerReceiver (mReceiver, filter1);
JPM
1
@JPM Sim, é. Eu estava indo para armazenar uma instância do meu receptor e verificar para cancelar o registro, se não for null. Mas como você apontou, eu vou com try catch. Ridículo.
9
Voto negativo para Android por não criar uma API para isso. +1 a você por fornecer uma solução funcional :)
Denys Vitali
1
O que é melhor? usando isso ou usando uma variável booleana como um sinalizador?
precisa saber é o seguinte
34

solução mais simples

no receptor:

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

em código:

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

anúncio 1

-- em resposta a:

Isso realmente não é tão elegante, porque você deve se lembrar de definir o sinalizador isRegistered depois de se registrar. - Rabino furtivo

- "maneira mais elegante" adicionou método no receptor para registrar e definir sinalizador

isso não funcionará Se você reiniciar o dispositivo ou se seu aplicativo foi morto pelo SO. - amin 6 horas atrás

@amin - veja a vida útil do receptor registrado no código (não sistema registrado por entrada de manifesto) :)

ceph3us
fonte
2
Esta é realmente uma solução elegante. FWIW, no Android Studio, quando tento estender o BroadcastReceiver, ele reclama e deseja substituir o onReceive. Felizmente, no meu caso, eu estava precisando estender o ScreenReceiver, que opera exatamente da maneira que o ceph3us descreve aqui.
MarkJoel60
Isso realmente não é tão elegante, porque você deve se lembrar de definir o sinalizador isRegistered depois de se registrar.
Rabino furtivo
Sim, embora você possa remover esta linha da seção "no código". myReceiver.isRegistered = true;
Rabino furtivo
isso não deveria ser uma classe abstrata? estender BroadcastReceiver requer que você implemente o método onReceive.
York Yang
@YorkYang adicionou informações em classe na parte inferior
ceph3us
27

Estou usando esta solução

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);
        }
    }
}
slinden77
fonte
2
haha, eu encontrá-los convenientes :) mais rápida visão geral sobre o formato e onde coisas começa e termina :) eacht a sua própria eu acho
slinden77
1
mmm, olhando para isso de acordo com o seu comentário, com boa aparência! Claro que estraguei a minha área de trabalho do Eclipse, mas não é preciso muito para que :)
slinden77
2
Ah, mude para o IntelliJ, depois que você se acostumar, o Eclipse parecerá muito velho;) No lado positivo, o novo Android Studio é apenas um IntelliJ com alguns complementos; portanto, se você está acostumado ao Intellij, o Android Studio irá fazer você se sentir em casa.
Martin Marconcini 28/05
2
@ MartínMarconcini bem, finalmente, fui forçado a mudar para o IntelliJ. Gosto muito, mas desprezo o fato de que é impossível trabalhar em 2 projetos simultaneamente.
precisa saber é o seguinte
1
Bem-vindo ao lado negro;) Eu tenho três Android Studio abertos agora com 3 projetos diferentes ... não sei qual é o seu problema de vários projetos, mas posso garantir que ele funciona com vários projetos. :)
Martin Marconcini
22

Você tem várias opções

  1. Você pode colocar uma bandeira em sua classe ou atividade. Coloque uma variável booleana em sua classe e veja este sinalizador para saber se você tem o Receiver registrado.

  2. Crie uma classe que estenda o receptor e lá você pode usar:

    1. O padrão Singleton para ter apenas uma instância dessa classe em seu projeto.

    2. Implemente os métodos para saber se o receptor é registrador.

chemalarrea
fonte
1
Fiz o mesmo, mas meu destinatário é o AppWidgetProvider e desejo receber mensagens SCREEN_ON_OFF - mas onDisabled () quando desregistoReceiver (this); - lança exceção.
Hb0
combinado primeira e segunda opção, uma bandeira na classe receptor, funciona muito
Gaeburider
você pode me dar um exemplo de código como im não conseguir o que ur exatamente fazendo ... seria b grande ajuda @chemalarrea
TapanHP
11

Você precisa usar try / catch:

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

Você pode fazer isso fácil ....

1) crie uma variável booleana ...

private boolean bolBroacastRegistred;

2) Ao registrar seu receptor de transmissão, defina-o como TRUE

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

3) Na onPause (), faça ...

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

Apenas isso, e agora, você não receberá mais mensagens de erro de exceção em onPause ().

Dica1: Sempre use o unregisterReceiver () em onPause () e não em onDestroy () Dica2: Não se esqueça de definir a variável bolBroadcastRegistred como FALSE ao executar o unregisterReceive ()

Sucesso!

Biruel Rick
fonte
6

Se você colocar isso no método onDestroy ou onStop. Eu acho que quando a atividade foi criada novamente, o MessageReciver não estava sendo criado.

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

}
eloirobe
fonte
3

Usei o Intent para informar ao Broadcast Receiver sobre a instância do manipulador do segmento de atividade principal e usei Message para passar uma mensagem para a atividade principal

Eu usei esse mecanismo para verificar se o Broadcast Receiver já está registrado ou não. Às vezes, é necessário quando você registra seu Broadcast Receiver dinamicamente e não deseja realizá-lo duas vezes ou apresenta ao usuário se o Broadcast Receiver estiver em execução.

Atividade principal:

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

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

Receptor de radiodifusão:

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

}

}
jarek
fonte
3

Pessoalmente, uso o método de chamar unregisterReceiver e engolir a exceção se for lançada. Concordo que isso é feio, mas o melhor método atualmente fornecido.

Eu levantei uma solicitação de recurso para obter um método booleano para verificar se um receptor está registrado adicionado à API do Android. Apoie-o aqui se você quiser vê-lo adicionado: https://code.google.com/p/android/issues/detail?id=73718

ojf
fonte
2

Estou com o seu problema, enfrentei o mesmo problema no meu Aplicativo. Eu estava chamando registerReceiver () várias vezes dentro do aplicativo.

Uma solução simples para esse problema é chamar o registerReceiver () na sua classe de aplicativo personalizado. Isso garantirá que o seu receptor de transmissão seja chamado apenas um em todo o ciclo de vida do aplicativo.

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

    }
}
Sameer Ranjan
fonte
1

Foi assim que eu fiz, é uma versão modificada da resposta dada por ceph3us e editada por slinden77 (entre outras coisas, removi os valores de retorno dos métodos que não precisava):

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

Em seguida, em uma classe de atividade:

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());
    }
}
Víctor Gil
fonte
1

eu coloquei esse código na minha atividade principal

Lista RegisteredReceivers = 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);
}
darkwater84
fonte
1

Para mim, o seguinte funcionou:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}
Benjamin Corben
fonte
0

Aqui está o que eu fiz para verificar se o Broadcaster já está registrado, mesmo se você fechar o aplicativo (finish ())

Primeiramente executando o aplicativo, envie uma transmissão primeiro, que retornará verdadeiro / falso, dependendo de o seu emissor ainda estar em execução ou não.

My Broadcaster

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

My MainActivity

// 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"));
}
janbee
fonte
0

Você pode usar o Dagger para criar uma referência desse receptor.

Primeiro forneça:

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

Em seguida, injete-o onde você precisar (usando constructorou campo injection)

e simplesmente passe para registerReceiver.

Também coloque-o em try/catchbloco também.

Mahdi-Malv
fonte
-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}
Kamta Sahu
fonte
1
Ordenou transmissão é completamente outra coisa ter um olhar para este link
Vivek Barai
-7

Basta verificar NullPointerException. Se o receptor não existir, então ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
Kasra
fonte
1
Como / onde isso gera um NPE?
DustinB
Na verdade, ele não gera erros quando é malsucedido. Infelizmente.
domenukk
2
Na verdade, ele lança uma IllegalArgumentException
portfoliobuilder