BroadcastReceiver com vários filtros ou vários BroadcastReceivers?

115

Tenho uma atividade Android que precisa capturar duas transmissões diferentes. Minha abordagem atual é ter um único BroadcastReceiverdentro da Activity e capturar as duas transmissões com ele:

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

Desejo executar refresh()apenas se minha atividade estiver visível na tela, mas desejo capturar INTENT_UPDATEe executar update()durante toda a vida da atividade, independentemente de a atividade estar visível ou não.

Não encontrei nenhuma maneira de cancelar o registro de apenas um dos dois filtros nos quais me inscrevi onCreate, então uso um sinalizador para habilitar ou desabilitar a ação a ser executada quando a INTENT_REFRESHtransmissão é capturada, dependendo do estado da Atividade.

A questão é : esta é a abordagem correta?

Ou seria melhor ter dois BroadcastReceivers separados da seguinte maneira:

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

E qual tem melhor desempenho?

Lorenzo Polidori
fonte

Respostas:

210

em vez disso, você pode fornecer dois filtros de intent diferentes:

filtrar apenas para atualização

IntentFilter filterRefresh = new IntentFilter(Params.INTENT_REFRESH);

filtrar para atualizar e atualizar

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

agora você pode alternar entre os filtros de intenção registrando e cancelando o registro do desejado, mas a implementação do seu receptor seria a mesma

waqaslam
fonte
@Waqas Você pode fornecer um exemplo de implementação do BroadcastReceiver que receberia várias intents? É apenas uma grande declaração if-then-else?
gonzobrains
2
@gonzobrains sim, para várias intents, você precisa usar um número igual de instruções if-else para filtrá-las
waqaslam
@Waqas Existe uma maneira de fazer isso dinamicamente para que você tenha um receptor de transmissão genérico e possa adicionar vários manipuladores a ele para não ter que modificar a estrutura básica cada vez que você adicionar uma nova intenção a ele?
gonzobrains
o que você quer dizer exatamente com "fazer isso dinamicamente" ? Simplesmente inclua todas as strings de ação dentro de seus filtros de intenção e execute if-else para identificar suas strings de ação necessárias.
waqaslam
3
Não entendo todos os votos positivos para essa resposta. Para o que o op estava tentando fazer, parece que 1 filtro de intent com 2 ações é adequado. O código do primeiro bloco de código da questão parece ser tudo o que é necessário.
hBrent
28

Para cada ação, crie IntentFilter e registre-o.

@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
fonte
4
Não deveria estar preocupado em ligar registerReceivervárias vezes e invocar unregisterReceiverapenas uma vez?
mr5 de
3
Se você chamar registerReceiver várias vezes e unregisterReceiver apenas uma vez, a instância anterior do receptor pode vazar. Portanto, a instância u registra e usa essa instância para cancelar o registro.
Pawan Yadav
2
Se você fosse se registrar várias vezes na mesma ação, eu diria que você deveria se preocupar.
stdout
1
Isso não deveria ser desencorajado? Seria útil para os desenvolvedores do Google lançar uma exceção quando você registrar o mesmo BroadcastReceiver mais de uma vez. Em vez disso, devemos adicionar várias ações ao filtro de intent.
TheRealChx101 de