Відповіді:
Я не впевнений, що API надає безпосередньо API, якщо врахувати цю тему :
Мені було цікаво те саме.
У моєму випадку у мене єBroadcastReceiver
реалізація, яка викликаєContext#unregisterReceiver(BroadcastReceiver)
передачу себе в якості аргументу після обробки наміру, який він отримує.
Існує невеликий шанс, щоonReceive(Context, Intent)
метод приймача викликається не один раз, оскільки він реєструється декількомаIntentFilters
, створюючи потенціал дляIllegalArgumentException
викинутого з ньогоContext#unregisterReceiver(BroadcastReceiver)
.У моєму випадку я можу зберігати приватного синхронізованого члена для перевірки перед викликом
Context#unregisterReceiver(BroadcastReceiver)
, але було б набагато чистіше, якби API надав метод перевірки.
Немає функції API, щоб перевірити, чи зареєстрований приймач. Вирішення проблеми полягає в тому, щоб ввести код уtry catch block as done below.
try {
//Register or UnRegister your broadcast receiver here
} catch(IllegalArgumentException e) {
e.printStackTrace();
}
null
. Але як ви вказали, я йду з цим try catch
. Смішно.
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
оголошення 1
- у відповідь на:
Це насправді не так елегантно, тому що вам потрібно пам’ятати, щоб встановити прапор isRegistered після реєстрації. - Стелс-рабин
- "більш елегантний спосіб" доданий метод у приймачі для реєстрації та встановлення прапора
це не буде працювати Якщо ви перезавантажите пристрій або якщо ваш додаток убитий ОС. - Амін 6 годин тому
@amin - див. термін експлуатації зареєстрованого приймача у коді (не система, зареєстрована за допомогою маніфесту) :)
Я використовую це рішення
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);
}
}
}
У вас є кілька варіантів
Ви можете поставити прапор у свій клас чи заняття. Помістіть бульову змінну у свій клас і подивіться на цей прапор, щоб знати, чи зареєстрований у вас приймач.
Створіть клас, який розширює приймач, і там ви можете використовувати:
Шаблон Singleton для вашого проекту має лише один екземпляр цього класу.
Реалізуйте методи для того, щоб знати, чи приймає ресивер.
Ви повинні використовувати try / catch:
try {
if (receiver!=null) {
Activity.this.unregisterReceiver(receiver);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
Зробити це можна легко….
1) створити булеву змінну ...
private boolean bolBroacastRegistred;
2) Коли ви реєструєте радіоприймач, встановіть його на ІСТИНУ
...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....
3) У режимі onPause () зробіть це ...
if (bolBroacastRegistred) {
this.unregisterReceiver(mReceiver);
bolBroacastRegistred = false
}
Просто так, і тепер ви більше не отримаєте повідомлення про помилку виключення на onPause ().
Порада1: Завжди використовуйте undegisterReceiver () у onPause (), а не onDestroy () Порада2: Не забудьте встановити змінну bolBroadcastRegistred на FALSE, коли запустіть undegisterReceive ()
Успіху!
Я використовував Намір, щоб повідомити широкомовному приймачу про екземпляр обробника основного потоку активності, а повідомлення використовував для передачі повідомлення Основній діяльності
Я використовував такий механізм, щоб перевірити, чи приймач мовлення вже зареєстрований чи ні. Іноді це потрібно, коли ви динамічно реєструєте приймач широкомовної передачі і не хочете робити це двічі або представляєте користувачеві, якщо транслятор приймача працює.
Основна діяльність:
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;
}
.............
}
Транслятор трансляції:
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();
}
}
.........
}
}
Особисто я використовую метод виклику undegisterReceiver та ковтання винятку, якщо він кинутий. Я погоджуюся, що це некрасиво, але найкращий метод, який зараз пропонується.
Я підняв запит на функцію отримання булевого методу, щоб перевірити, чи зареєстрований ресивер, доданий до Android API. Підтримуйте його тут, якщо ви хочете, щоб його додали: https://code.google.com/p/android/isissue/detail?id=73718
Я розумію вашу проблему, я зіткнувся з тією ж проблемою в моєму додатку. Я дзвонив registerReceiver () кілька разів у програмі.
Просте рішення цієї проблеми - викликати registerReceiver () у вашому користувальницькому класі додатків. Це забезпечить, що ваш приймач широкомовної програми буде називатися лише одним упродовж усього життєвого циклу програми.
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);
}
}
Ось як я це зробив, це модифікована версія відповіді, яку дав ceph3us та відредагував slinden77 (серед іншого я видалив зворотні значення методів, які мені не потрібні):
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
}
}
}
Потім на занятті:
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());
}
}
Я ставлю цей код у своїй діяльності батьків
Список зареєстрованих приймачів = новий 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);
}
Для мене працювали наступні:
if (receiver.isOrderedBroadcast()) {
requireContext().unregisterReceiver(receiver);
}
Ось, що я зробив, щоб перевірити, чи мовник уже зареєстрований, навіть якщо ви закрили заявку (закінчити ())
Перш ніж запустити вашу програму, надішліть трансляцію спочатку, вона поверне справжнє / хибне, залежно від того, чи ваш мовник все ще працює чи ні.
Мій мовник
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;
}
}
}
Моя головна активність
// 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"));
}
Ви можете використовувати Dagger для створення посилання на цей приймач.
Спочатку надайте:
@Provides
@YourScope
fun providesReceiver(): NotificationReceiver{
return NotificationReceiver()
}
Потім введіть його там, де вам потрібно (використовуючи constructor
або поле injection
)
і просто передати його registerReceiver
.
Також поставте його в try/catch
блок.
if( receiver.isOrderedBroadcast() ){
// receiver object is registered
}
else{
// receiver object is not registered
}
Просто перевірте NullPointerException. Якщо приймача не існує, то ...
try{
Intent i = new Intent();
i.setAction("ir.sss.smsREC");
context.sendBroadcast(i);
Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
e.getMessage();
}