Respostas:
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 umaBroadcastReceiver
implementação que chamaContext#unregisterReceiver(BroadcastReceiver)
passando-se como o argumento depois de manipular o Intent que ele recebe.
Há uma pequena chance de que oonReceive(Context, Intent)
método do receptor seja chamado mais de uma vez, uma vez que é registrado com múltiplosIntentFilters
, criando o potencial paraIllegalArgumentException
ser jogadoContext#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.
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();
}
null
. Mas como você apontou, eu vou com try catch
. Ridículo.
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 :)
...
}
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) :)
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);
}
}
}
Você tem várias opções
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.
Crie uma classe que estenda o receptor e lá você pode usar:
O padrão Singleton para ter apenas uma instância dessa classe em seu projeto.
Implemente os métodos para saber se o receptor é registrador.
Você precisa usar try / catch:
try {
if (receiver!=null) {
Activity.this.unregisterReceiver(receiver);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
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!
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);
}
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();
}
}
.........
}
}
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
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);
}
}
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());
}
}
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);
}
Para mim, o seguinte funcionou:
if (receiver.isOrderedBroadcast()) {
requireContext().unregisterReceiver(receiver);
}
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"));
}
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 constructor
ou campo injection
)
e simplesmente passe para registerReceiver
.
Também coloque-o em try/catch
bloco também.
if( receiver.isOrderedBroadcast() ){
// receiver object is registered
}
else{
// receiver object is not registered
}
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();
}