Як перевірити, чи приймач зареєстрований в 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.