BroadcastReceiver z wieloma filtrami lub wieloma BroadcastReceiver?


115

Mam działanie na Androida, które musi przechwytywać dwie różne transmisje. Moje obecne podejście polega na tym, aby mieć singiel BroadcastReceiverw ramach działania i złapać za jego pomocą obie transmisje:

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

Chcę wykonać refresh()tylko wtedy, gdy moje działanie jest widoczne na ekranie, ale chcę je przechwycić INTENT_UPDATEi wykonać update()przez cały czas jego trwania, niezależnie od tego, czy działanie jest widoczne, czy nie.

Nie znalazłem sposobu na wyrejestrowanie tylko jednego z dwóch filtrów, w których się rejestruję onCreate, więc używam flagi, aby włączyć lub wyłączyć akcję, która ma być wykonana po przechwyceniu INTENT_REFRESHtransmisji, w zależności od stanu działania.

Pytanie brzmi : czy to jest właściwe podejście?

A może lepiej byłoby mieć dwa oddzielne odbiorniki BroadcastReceivers w następujący sposób:

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

A który z nich ma lepszą wydajność?

Odpowiedzi:


210

zamiast tego możesz podać dwa różne filtry intencji:

filtr tylko do odświeżenia

IntentFilter filterRefresh = new IntentFilter(Params.INTENT_REFRESH);

filtr do odświeżania i aktualizacji

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

teraz możesz przełączać się między filtrami intencji, rejestrując i wyrejestrowując żądany, ale implementacja twojego odbiorcy byłaby taka sama


@Waqas Czy możesz podać przykładową implementację BroadcastReceiver, która otrzymałaby wiele intencji? Czy to tylko duże stwierdzenie „jeśli-to-jeszcze”?
gonzobrains

2
@gonzobrains tak, w przypadku wielu zamiarów musisz użyć równej liczby instrukcji if-else, aby je odfiltrować
waqaslam

@Waqas Czy istnieje sposób, aby zrobić to dynamicznie, aby mieć ogólny odbiornik rozgłoszeniowy i dodać do niego wiele programów obsługi, aby nie musieć modyfikować podstawowego szkieletu za każdym razem, gdy dodajesz do niego nową intencję?
gonzobrains

co dokładnie masz na myśli, mówiąc „robić to dynamicznie” ? Po prostu umieść wszystkie ciągi akcji wewnątrz swoich filtrów intencji i wykonaj if-else, aby zidentyfikować wymagane ciągi akcji.
waqaslam

3
Nie rozumiem wszystkich głosów za tą odpowiedzią. Wydaje się, że do tego, co próbował zrobić operator, wystarczy 1 filtr intencji z 2 akcjami. Kod z pierwszego bloku kodu w pytaniu wydaje się być wszystkim, czego potrzeba.
hBrent,

28

Dla każdej akcji utwórz IntentFilter i zarejestruj go.

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

}

4
Czy nie powinienem się martwić, dzwoniąc registerReceiverkilka razy i wywołując unregisterReceivertylko jeden raz?
mr5

3
Jeśli u call registerReceiver wielokrotnie i unregisterReceiver tylko raz, to poprzednia instancja odbiornika może przeciekać. Więc instancja u rejestruje się, a następnie używa tej instancji do wyrejestrowania.
Pawan Yadav,

2
Gdybyś miał rejestrować się wiele razy na tę samą akcję, powiedziałbym, że powinieneś się martwić.
wyjście

1
Nie należy tego zniechęcać? Byłoby pomocne dla programistów Google, aby zgłosić wyjątek, gdy rejestrujesz ten sam BroadcastReceiver więcej niż raz. Zamiast tego powinniśmy dodać wiele akcji do filtra intencji.
TheRealChx101
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.