web-dev-qa-db-fra.com

Comment vérifier si Receiver est enregistré dans Android?

Je dois vérifier si mon récepteur enregistré est toujours enregistré, sinon comment puis-je vérifier les méthodes?

222
Mikey

Je ne suis pas sûr que l'API fournisse directement une API, si vous considérez ce fil :

Je me demandais la même chose.
Dans mon cas, j'ai une implémentation BroadcastReceiver qui appelle Context#unregisterReceiver(BroadcastReceiver) se passant lui-même en tant qu'argument après avoir traité l'intention qu'il reçoit.
Il y a un petit risque que la méthode onReceive(Context, Intent) du destinataire soit appelée plus d’une fois, puisqu’il est enregistré avec plusieurs IntentFilters, créant le risque qu’un IllegalArgumentException soit éjecté de Context#unregisterReceiver(BroadcastReceiver).

Dans mon cas, je peux stocker un membre synchronisé privé à vérifier avant d'appeler Context#unregisterReceiver(BroadcastReceiver), mais ce serait beaucoup plus propre si l’API fournissait une méthode de contrôle. 

62
VonC

Il n'y a pas de fonction API permettant de vérifier si un destinataire est enregistré. La solution consiste à mettre votre code dans un try catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
280
Daniel Velkov

solution la plus simple

dans le récepteur:

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

dans du code:

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

modifier I

-- en réponse à 

Ce n’est vraiment pas élégant parce que vous devez vous rappeler de régler le isRegistered flag après votre inscription. - Rabbin furtif

- "méthode plus ellegant" ajouté méthode dans le récepteur pour enregistrer et définir le drapeau 

29
ceph3us

J'utilise cette solution

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);
        }
    }
}
27
slinden77

Vous avez plusieurs options

  1. Vous pouvez mettre un drapeau dans votre classe ou activité. Mettez une variable booléenne dans votre classe et regardez ce drapeau pour savoir si vous avez enregistré le récepteur.

  2. Créez une classe qui étend le récepteur et vous pouvez y utiliser:

    1. Motif Singleton pour seulement avoir une instance de cette classe dans votre projet.

    2. Implémentez les méthodes pour savoir si le récepteur est enregistré.

22
chemalarrea

Vous devez utiliser try/catch:

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

Vous pouvez le faire facilement ....

1) créer une variable booléenne ...

private boolean bolBroacastRegistred;

2) Lorsque vous enregistrez votre émetteur-récepteur, réglez-le sur VRAI.

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

3) Dans le onPause () faites-le ...

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

Juste et maintenant, vous ne recevrez plus de message d'erreur d'exception sur onPause ().

Astuce 1: utilisez toujours unregisterReceiver () dans onPause () et non dans onDestroy () Astuce 2: n'oubliez pas de définir la variable bolBroadcastRegistred sur FALSE lorsque vous exécutez unregisterReceive ()

Succès!

7
Biruel Rick

Si vous mettez ceci sur la méthode onDestroy ou onStop. Je pense que lorsque l'activité a été créée à nouveau, MessageReciver n'était pas en cours de création.

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

}
5
eloirobe

J'ai utilisé Intention pour informer Broadcast Receiver de l'instance de gestionnaire du fil d'activité principal et ai utilisé Message pour transmettre un message à l'activité principale.

J'ai utilisé un tel mécanisme pour vérifier si Broadcast Receiver est déjà enregistré ou non. Parfois, cela est nécessaire lorsque vous enregistrez votre récepteur de radiodiffusion de manière dynamique et que vous ne voulez pas le faire deux fois, ou que vous présentez à l'utilisateur si le récepteur de diffusion est en cours d'exécution.

Activité principale:

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

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

Récepteur de diffusion:

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
jarek

Je comprends votre problème, j'ai rencontré le même problème dans mon application. J'appelais registerReceiver () plusieurs fois dans l'application. 

Une solution simple à ce problème consiste à appeler registerReceiver () dans votre classe d'application personnalisée. Cela garantira que votre récepteur de radiodiffusion sera appelé un seul dans l'ensemble du cycle de vie de votre application.

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

    }
}
2
Sameer Ranjan

Personnellement, j'utilise la méthode qui consiste à appeler unregisterReceiver et à avaler l'exception si elle est levée. Je suis d'accord c'est moche mais la meilleure méthode actuellement fournie.

J'ai lancé une demande de fonctionnalité pour obtenir une méthode booléenne permettant de vérifier si un récepteur est enregistré et ajouté à l'API Android. Soutenez-le ici si vous voulez le voir ajouté: https://code.google.com/p/Android/issues/detail?id=73718

2
ojf

je mets ce code dans mon activité parent

Liste 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);
}
1
darkwater84

Vous pouvez utiliser Dagger pour créer une référence de ce récepteur.

D'abord, fournissez-le:

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

Puis injectez-le où vous avez besoin (en utilisant constructor ou un champ injection)

et passez-le simplement à registerReceiver.

Mettez-le également dans le bloc try/catch.

0
Mahdi-Malv

Voici comment je l'ai fait, c'est une version modifiée de la réponse donnée par ceph3us et modifiée par slinden77 (entre autres, j'ai supprimé les valeurs de retour des méthodes dont je n'avais pas besoin):

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

Puis sur une classe d'activité:

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

Voici ce que j'ai fait pour vérifier si le diffuseur est déjà enregistré, même si vous fermez votre application (finish ())

Tout d'abord en exécutant votre application, envoyez une diffusion en premier, elle retournera vrai/faux, selon que votre diffuseur fonctionne toujours ou non.

Mon diffuseur

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

Mon activité principale

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