BroadcastReceiver avec plusieurs filtres ou plusieurs BroadcastReceiver?

115

J'ai une activité Android qui doit capturer deux diffusions différentes. Mon approche actuelle consiste à en avoir un BroadcastReceiverdans l'activité et à capturer les deux diffusions avec:

public class MyActivity extends Activity {
    private MyActivity.BroadcastListener mBroadcastListener;
    private boolean mIsActivityPaused = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mylayout);

        // Create the broadcast listener and register the filters
        mIsActivityPaused = false;
        mBroadcastListener = new BroadcastListener();

        IntentFilter filter = new IntentFilter();
        filter.addAction(Params.INTENT_REFRESH);
        filter.addAction(Params.INTENT_UPDATE);
        registerReceiver(mBroadcastListener, filter);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mIsActivityPaused = false;
    }

    @Override
    protected void onPause() {
        super.onPause();
        mIsActivityPaused = true;
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(mBroadcastListener);
        super.onDestroy();
    }

    private void refresh() {
        // refresh
    }

    private void update() {
        // update
    }

    private class BroadcastListener extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Params.INTENT_REFRESH && !mIsActivityPaused)) {
                refresh();
            } else if (intent.getAction().equals(Params.INTENT_UPDATE)) {
                update();
            }
        }
    }
}

Je souhaite exécuter refresh()uniquement si mon activité est visible à l'écran, mais je souhaite capturer INTENT_UPDATEet exécuter update()pendant toute la durée de vie de l'activité, que l'activité soit visible ou non.

Je n'ai trouvé aucun moyen de désinscrire un seul des deux filtres dans lesquels je m'inscris onCreate, j'utilise donc un indicateur pour activer ou désactiver l'action à exécuter lorsque la INTENT_REFRESHdiffusion est interceptée, en fonction de l'état de l'activité.

La question est : est-ce la bonne approche?

Ou serait-il préférable d'avoir deux BroadcastReceivers distincts comme suit:

public class MyActivity extends Activity {
    private MyActivity.BroadcastListenerRefresh mBroadcastListenerRefresh;
    private MyActivity.BroadcastListenerUpdate mBroadcastListenerUpdate;
    private boolean mIsBroadcastListenerRefreshRegistered = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create the broadcast listeners
        mBroadcastListenerRefresh = new BroadcastListenerRefresh();
        mBroadcastListenerUpdate = new BroadcastListenerUpdate();

        registerReceiver(mBroadcastListenerRefresh, new IntentFilter(Params.INTENT_REFRESH));
        registerReceiver(mBroadcastListenerUpdate, new IntentFilter(Params.INTENT_UPDATE));
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mBroadcastListenerRefresh != null && !mIsBroadcastListenerRefreshRegistered) {
            registerReceiver(mBroadcastListenerRefresh, new IntentFilter(Params.INTENT_REFRESH));
            mIsBroadcastListenerRefreshRegistered = true;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mBroadcastListenerRefresh != null && mIsBroadcastListenerRefreshRegistered) {
            unregisterReceiver(mBroadcastListenerRefresh);
            mIsBroadcastListenerRefreshRegistered = false;
        }
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(mBroadcastListenerRefresh);
        unregisterReceiver(mBroadcastListenerUpdate);
        super.onDestroy();
    }

    private void refresh() {
        // refresh
    }

    private void update() {
        // update
    }

    private class BroadcastListenerRefresh extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Params.INTENT_REFRESH)) {
                refresh();
            }
        }
    }

    private class BroadcastListenerUpdate extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Params.INTENT_UPDATE)) {
                update();
            }
        }
    }
}

Et lequel a de meilleures performances?

Lorenzo Polidori
la source

Réponses:

210

à la place, vous pouvez fournir deux filtres d'intention différents:

filtre pour actualisation uniquement

IntentFilter filterRefresh = new IntentFilter(Params.INTENT_REFRESH);

filtre pour actualisation et mise à jour

IntentFilter filterRefreshUpdate = new IntentFilter();
filterRefreshUpdate.addAction(Params.INTENT_REFRESH);
filterRefreshUpdate.addAction(Params.INTENT_UPDATE);

maintenant, vous pouvez basculer entre les filtres d'intention en enregistrant et en désenregistrant celui souhaité, mais l'implémentation de votre récepteur serait la même

waqaslam
la source
@Waqas Pouvez-vous fournir un exemple d'implémentation de BroadcastReceiver qui recevrait plusieurs intentions? Est-ce juste une grande déclaration if-then-else?
gonzobrains
2
@gonzobrains oui, pour plusieurs intentions, vous devez utiliser un nombre égal d'instructions if-else pour les filtrer
waqaslam
@Waqas Existe-t-il un moyen de le faire de manière dynamique afin que vous ayez un récepteur de diffusion générique et que vous puissiez y ajouter plusieurs gestionnaires afin de ne pas avoir à modifier le cadre de base chaque fois que vous y ajoutez une nouvelle intention?
gonzobrains
qu'entendez-vous exactement par «faire cela dynamiquement» ? Incluez simplement toutes les chaînes d'action dans vos filtres d'intention et exécutez if-else pour identifier vos chaînes d'action requises.
waqaslam
3
Je ne comprends pas tous les votes positifs pour cette réponse. Pour ce que l'op essayait de faire, il semble qu'un filtre d'intention avec 2 actions soit adéquat. Le code du premier bloc de code de la question semble être tout ce dont vous avez besoin.
hBrent du
28

Pour chaque action, créez IntentFilter et enregistrez-le.

@Override
protected void onResume() {

    super.onResume();

    BroadcastListener receiver = new BroadcastListener();

    // Register the filter for listening broadcast.
    IntentFilter filterRefresh = new IntentFilter(Params.INTENT_REFRESH);
    IntentFilter filterUpdate = new IntentFilter(Params.INTENT_UPDATE);

    registerReceiver(receiver, filterRefresh);
    registerReceiver(receiver, filterUpdate);
} 



private class BroadcastListener extends BroadcastReceiver {
    public void onReceive(Context ctx, Intent intent) {

        if (intent.getAction().equals(Params.INTENT_UPDATE)) {
            update();
        } else if(intent.getAction().equals(Params.INTENT_REFRESH)) {
            refresh();
        }
    }

}
Pawan Yadav
la source
4
Ne devrais-je pas m'inquiéter d'appeler registerReceiverplusieurs fois et d'invoquer unregisterReceiverune seule fois?
mr5
3
Si vous appelez plusieurs fois registerReceiver et unregisterReceiver une seule fois, l'instance précédente du récepteur peut fuir. Ainsi, l'instance u s'inscrit ensuite en utilisant cette instance pour se désinscrire.
Pawan Yadav
2
Si vous deviez vous inscrire plusieurs fois sur la même action, je dirais que vous devriez vous inquiéter.
stdout
1
Cela ne devrait-il pas être découragé? Il serait utile que les développeurs de Google lancent une exception lorsque vous enregistrez le même BroadcastReceiver plus d'une fois. Au lieu de cela, nous devons ajouter plusieurs actions au filtre d'intention.
TheRealChx101