Як перевірити, чи приймач зареєстрований в Android?


Відповіді:


68

Я не впевнений, що API надає безпосередньо API, якщо врахувати цю тему :

Мені було цікаво те саме.
У моєму випадку у мене є BroadcastReceiverреалізація, яка викликає Context#unregisterReceiver(BroadcastReceiver)передачу себе в якості аргументу після обробки наміру, який він отримує.
Існує невеликий шанс, що onReceive(Context, Intent)метод приймача викликається не один раз, оскільки він реєструється декількома IntentFilters, створюючи потенціал для IllegalArgumentExceptionвикинутого з нього Context#unregisterReceiver(BroadcastReceiver).

У моєму випадку я можу зберігати приватного синхронізованого члена для перевірки перед викликом Context#unregisterReceiver(BroadcastReceiver), але було б набагато чистіше, якби API надав метод перевірки.


313

Немає функції API, щоб перевірити, чи зареєстрований приймач. Вирішення проблеми полягає в тому, щоб ввести код уtry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
це облом ... :(
Сандер Верслейс

4
Найсмішніше те, що не вдається отримати помилку під час цього виклику BroadcastReceiver для registerReceiver (mReceiver, filter1);
JPM

1
@JPM Так. Я збирався зберігати екземпляр мого приймача і перевіряти, чи не відреєструвати його, якщо його немає null. Але як ви вказали, я йду з цим try catch. Смішно.

9
Перейдіть на Android, щоб не створити API для цього. +1 вам за надання робочого рішення :)
Denys Vitali

1
Що краще? використовуючи це або використовуючи булева змінна як прапор?
DAVIDBALAS1

34

найпростіше рішення

в приймачі:

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 - див. термін експлуатації зареєстрованого приймача у коді (не система, зареєстрована за допомогою маніфесту) :)


2
Це справді елегантне рішення. FWIW, в студії Android, коли я намагаюся розширити BroadcastReceiver, він скаржиться і хоче перекрити OnReceive. На щастя, в моєму випадку мені потрібно було розширити ScreenReceiver, який працює саме так, як описує тут ceph3us.
MarkJoel60

Це насправді не так елегантно, тому що вам потрібно пам’ятати, щоб встановити прапор isRegistered після реєстрації.
Стелс-рабин

Так, хоча ви можете видалити цей рядок із розділу "за кодом". myReceiver.isRegistered = вірно;
Стелс-рабин

чи не повинен це бути абстрактний клас? розширення BroadcastReceiver вимагає від вас застосувати метод onReceive.
Йорк Ян

@YorkYang додав інформацію в класі внизу
ceph3us

27

Я використовую це рішення

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

2
ха-ха, я вважаю їх зручними :) Швидший огляд формату і де починаються і закінчуються речі :) кожен до свого, я здогадуюсь
slinden77

1
ммм, розглядаючи це відповідно до Вашого коментаря, добре виглядаючи! Звичайно, це накрутило мою робочу область Eclipse, але для цього не потрібно багато чого
slinden77

2
О, переходьте на IntelliJ, як тільки ви звикнете до цього, Eclipse відчуває себе по-справжньому;) З іншого боку, нова Android Studio - це лише IntelliJ з кількома додатками, тому якщо ви звикли до Intellij, Android Studio буде змусити себе почувати себе як вдома.
Мартін Маркончіні

2
@ MartínMarconcini добре, нарешті, я був змушений перейти на IntelliJ. Мені це дуже подобається, але я зневажаю той факт, що неможливо працювати в двох проектах одночасно.
slinden77

1
Ласкаво просимо до темної сторони;) У мене зараз три Android Studio відкриті з трьома різними проектами… не впевнений, у чому полягає ваша проблема з декількома проектами, але можу запевнити, що вона працює з декількома проектами. :)
Мартін Маркончіні

22

У вас є кілька варіантів

  1. Ви можете поставити прапор у свій клас чи заняття. Помістіть бульову змінну у свій клас і подивіться на цей прапор, щоб знати, чи зареєстрований у вас приймач.

  2. Створіть клас, який розширює приймач, і там ви можете використовувати:

    1. Шаблон Singleton для вашого проекту має лише один екземпляр цього класу.

    2. Реалізуйте методи для того, щоб знати, чи приймає ресивер.


1
Я зробив те саме, але мій приймач - це AppWidgetProvider, і я хочу отримувати повідомлення SCREEN_ON_OFF - але onDisabled (), коли я відреєстраторReceiver (це); - це кидає виняток.
hB0

комбінований перший та другий варіант, прапор у класі приймача, чудово працює
Gaeburider

чи можете ви надати мені приклад коду, оскільки я не отримую, що саме роблять ур ... Буде велика допомога @chemalarrea
TapanHP

11

Ви повинні використовувати try / catch:

try {
    if (receiver!=null) {
        Activity.this.unregisterReceiver(receiver);
    }
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}

7

Зробити це можна легко….

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

Успіху!


6

Якщо ви поставите це на метод onDestroy або onStop. Я думаю, що коли діяльність знову була створена, MessageReciver не створювався.

@Override 
public void onDestroy (){
    super.onDestroy();
LocalBroadcastManager.getInstance(context).unregisterReceiver(mMessageReceiver);

}

3

Я використовував Намір, щоб повідомити широкомовному приймачу про екземпляр обробника основного потоку активності, а повідомлення використовував для передачі повідомлення Основній діяльності

Я використовував такий механізм, щоб перевірити, чи приймач мовлення вже зареєстрований чи ні. Іноді це потрібно, коли ви динамічно реєструєте приймач широкомовної передачі і не хочете робити це двічі або представляєте користувачеві, якщо транслятор приймача працює.

Основна діяльність:

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

}

}

3

Особисто я використовую метод виклику undegisterReceiver та ковтання винятку, якщо він кинутий. Я погоджуюся, що це некрасиво, але найкращий метод, який зараз пропонується.

Я підняв запит на функцію отримання булевого методу, щоб перевірити, чи зареєстрований ресивер, доданий до Android API. Підтримуйте його тут, якщо ви хочете, щоб його додали: https://code.google.com/p/android/isissue/detail?id=73718


2

Я розумію вашу проблему, я зіткнувся з тією ж проблемою в моєму додатку. Я дзвонив 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);

    }
}

1

Ось як я це зробив, це модифікована версія відповіді, яку дав 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());
    }
}

1

Я ставлю цей код у своїй діяльності батьків

Список зареєстрованих приймачів = новий 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);
}


0

Ось, що я зробив, щоб перевірити, чи мовник уже зареєстрований, навіть якщо ви закрили заявку (закінчити ())

Перш ніж запустити вашу програму, надішліть трансляцію спочатку, вона поверне справжнє / хибне, залежно від того, чи ваш мовник все ще працює чи ні.

Мій мовник

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

0

Ви можете використовувати Dagger для створення посилання на цей приймач.

Спочатку надайте:

@Provides
@YourScope
fun providesReceiver(): NotificationReceiver{
    return NotificationReceiver()
}

Потім введіть його там, де вам потрібно (використовуючи constructorабо поле injection)

і просто передати його registerReceiver.

Також поставте його в try/catchблок.



-7

Просто перевірте NullPointerException. Якщо приймача не існує, то ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}

1
Як / куди це кидає NPE?
ДастінБ

Він не кидає жодних помилок, коли насправді невдалий. Сумно.
domenukk

2
Насправді, це кидає IllegalArgumentException
портфель будівельника
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.