Risposte:
Non sono sicuro che l'API fornisca direttamente un'API, se si considera questo thread :
Mi chiedevo la stessa cosa.
Nel mio caso hoBroadcastReceiver
un'implementazione che chiamaContext#unregisterReceiver(BroadcastReceiver)
passare se stessa come argomento dopo aver gestito l'intento che riceve.
C'è una piccola possibilità che ilonReceive(Context, Intent)
metodo del ricevitore sia chiamato più di una volta, poiché è registrato con piùIntentFilters
, creando il potenziale perIllegalArgumentException
essere scartatoContext#unregisterReceiver(BroadcastReceiver)
.Nel mio caso, posso archiviare un membro sincronizzato privato da controllare prima di chiamare
Context#unregisterReceiver(BroadcastReceiver)
, ma sarebbe molto più pulito se l'API fornisse un metodo di controllo.
Non esiste una funzione API per verificare se un ricevitore è registrato. La soluzione alternativa è inserire il codice in atry catch block as done below.
try {
//Register or UnRegister your broadcast receiver here
} catch(IllegalArgumentException e) {
e.printStackTrace();
}
null
. Ma come hai sottolineato, vado avanti try catch
. Ridicolo.
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
annuncio 1
-- in risposta a:
Questo non è poi così elegante perché devi ricordarti di impostare il flag isRegistered dopo la registrazione. - Rabbino invisibile
- "ricevitore più ellegante" ha aggiunto il metodo nel ricevitore per registrare e impostare il flag
questo non funzionerà Se riavvii il dispositivo o se l'app è stata uccisa dal sistema operativo. - Amin 6 ore fa
@amin - vedi la durata del codice in (non il sistema registrato dalla voce manifest) ricevitore registrato :)
Sto usando questa soluzione
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);
}
}
}
Hai diverse opzioni
Puoi mettere una bandiera nella tua classe o attività. Inserisci una variabile booleana nella tua classe e osserva questo flag per sapere se hai il ricevitore registrato.
Crea una classe che estende il ricevitore e lì puoi usare:
Il modello Singleton ha solo un'istanza di questa classe nel tuo progetto.
Implementare i metodi per sapere se il ricevitore è registrato.
Devi usare try / catch:
try {
if (receiver!=null) {
Activity.this.unregisterReceiver(receiver);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
Puoi farlo facilmente ....
1) crea una variabile booleana ...
private boolean bolBroacastRegistred;
2) Quando si registra il ricevitore di trasmissione, impostarlo su TRUE
...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....
3) In onPause () fallo ...
if (bolBroacastRegistred) {
this.unregisterReceiver(mReceiver);
bolBroacastRegistred = false
}
Proprio così, e ora, non riceverai più messaggi di errore di eccezione su onPause ().
Suggerimento1: utilizzare sempre unregisterReceiver () in onPause () non in onDestroy () Suggerimento2: non dimenticare di impostare la variabile bolBroadcastRegistred su FALSE quando si esegue unregisterReceive ()
Successo!
Ho usato Intent per informare Broadcast Receiver sull'istanza di Handler del thread principale delle attività e ho usato Message per passare un messaggio all'attività principale
Ho usato tale meccanismo per verificare se Broadcast Receiver è già registrato o meno. A volte è necessario quando si registra dinamicamente il ricevitore Broadcast e non si desidera farlo due volte o si presenta all'utente se Broadcast Receiver è in esecuzione.
Attività 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;
}
.............
}
Ricevitore broadcast:
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();
}
}
.........
}
}
Personalmente uso il metodo per chiamare unregisterReceiver e ingoiare l'eccezione se viene generata. Sono d'accordo che sia brutto ma il miglior metodo attualmente fornito.
Ho sollevato una richiesta di funzionalità per ottenere un metodo booleano per verificare se un ricevitore è registrato aggiunto all'API Android. Supportalo qui se vuoi vederlo aggiunto: https://code.google.com/p/android/issues/detail?id=73718
Ottengo il tuo problema, ho riscontrato lo stesso problema nella mia applicazione. Stavo chiamando registerReceiver () più volte all'interno dell'applicazione.
Una soluzione semplice a questo problema è chiamare registerReceiver () nella propria classe di applicazione personalizzata. Questo assicurerà che il tuo ricevitore Broadcast verrà chiamato solo uno nell'intero ciclo di vita dell'applicazione.
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);
}
}
È così che l'ho fatto, è una versione modificata della risposta data da ceph3us e modificata da slinden77 (tra le altre cose ho rimosso valori di ritorno di metodi che non mi servivano):
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
}
}
}
Quindi su una classe Activity:
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());
}
}
ho inserito questo codice nella mia attività genitore
Elenco RegisterReceivers = 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);
}
Per me ha funzionato:
if (receiver.isOrderedBroadcast()) {
requireContext().unregisterReceiver(receiver);
}
Ecco cosa ho fatto per verificare se l'emittente è già registrata, anche se chiudi l'applicazione (finish ())
Prima di avviare l'applicazione, inviare prima una trasmissione che restituirà vero / falso dipende dal fatto che l'emittente sia ancora in esecuzione o meno.
La mia emittente
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;
}
}
}
La mia attività 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"));
}
Puoi usare il Pugnale per creare un riferimento di quel ricevitore.
Prima forniscilo:
@Provides
@YourScope
fun providesReceiver(): NotificationReceiver{
return NotificationReceiver()
}
Quindi iniettalo dove ti serve (usando constructor
o campo injection
)
e semplicemente passalo a registerReceiver
.
Mettilo anche in try/catch
blocco.
if( receiver.isOrderedBroadcast() ){
// receiver object is registered
}
else{
// receiver object is not registered
}
Basta controllare NullPointerException. Se il ricevitore non esiste, quindi ...
try{
Intent i = new Intent();
i.setAction("ir.sss.smsREC");
context.sendBroadcast(i);
Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
e.getMessage();
}