Bagaimana cara memeriksa apakah Receiver terdaftar di Android?

Jawaban:

68

Saya tidak yakin API menyediakan API secara langsung, jika Anda mempertimbangkan utas ini :

Saya bertanya-tanya hal yang sama.
Dalam kasus saya, saya memiliki BroadcastReceiverimplementasi yang menyebut Context#unregisterReceiver(BroadcastReceiver)passing itu sendiri sebagai argumen setelah menangani Intent yang diterimanya.
Ada kemungkinan kecil bahwa metode penerima onReceive(Context, Intent)dipanggil lebih dari sekali, karena metode ini terdaftar dengan banyak IntentFilters, menciptakan potensi untuk IllegalArgumentExceptiondilemparkan Context#unregisterReceiver(BroadcastReceiver).

Dalam kasus saya, saya dapat menyimpan anggota yang disinkronkan pribadi untuk memeriksa sebelum menelepon Context#unregisterReceiver(BroadcastReceiver), tetapi akan jauh lebih bersih jika API menyediakan metode pemeriksaan.

VONC
sumber
313

Tidak ada fungsi API untuk memeriksa apakah penerima terdaftar. Solusinya adalah dengan meletakkan kode Anda di atry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
Daniel Velkov
sumber
83
itu menyedihkan ... :(
Sander Versluys
4
Lucunya, itu tidak menangkap kesalahan untuk panggilan ini ke BroadcastReceiver untuk registerReceiver (mReceiver, filter1);
JPM
1
@ JPM Ya itu. Saya akan menyimpan instance dari receiver saya dan memeriksa untuk membatalkan registrasi jika tidak null. Tapi seperti yang Anda tunjukkan, saya akan ikut try catch. Konyol.
9
Turunkan unduhan ke Android karena tidak membuat API untuk itu. +1 kepada Anda untuk memberikan solusi yang bekerja :)
Denys Vitali
1
Apa yang lebih baik? menggunakan ini atau menggunakan variabel boolean sebagai flag?
DAVIDBALAS1
34

solusi paling sederhana

dalam penerima:

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 :)
    ...
}

dalam kode:

MyReceiver myReceiver = new MyReceiver();
myReceiver.register(Context, IntentFilter); // register 
myReceiver.unregister(Context); // unregister 

iklan 1

- sebagai balasan ke:

Ini benar-benar tidak elegan karena Anda harus ingat untuk mengatur bendera isRegistered setelah Anda mendaftar. - Rabi Siluman

- "cara yang lebih ellegant" menambahkan metode pada receiver untuk mendaftar dan mengatur flag

ini tidak akan berfungsi Jika Anda me-restart perangkat atau jika aplikasi Anda terbunuh oleh OS. - amin 6 jam yang lalu

@amin - lihat masa pakai kode (bukan sistem terdaftar dengan entri manifes) penerima terdaftar :)

ceph3us
sumber
2
Ini benar-benar solusi yang elegan. FWIW, di Android Studio, ketika saya mencoba memperluas BroadcastReceiver, ia mengeluh dan ingin mengganti onReceive. Untungnya, dalam kasus saya, saya perlu memperpanjang ScreenReceiver, yang beroperasi persis seperti yang dijelaskan ceph3us di sini.
MarkJoel60
Ini benar-benar tidak elegan karena Anda harus ingat untuk mengatur bendera isRegistered setelah Anda mendaftar.
Stealth Rabbi
Ya, meskipun Anda dapat menghapus baris ini dari bagian "dalam kode" Anda. myReceiver.isRegistered = true;
Stealth Rabbi
Bukankah ini kelas abstrak? memperluas BroadcastReceiver mengharuskan Anda untuk menerapkan metode onReceive.
York Yang
@YorkYang menambahkan info di kelas di bagian bawah
ceph3us
27

Saya menggunakan solusi ini

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);
        }
    }
}
slinden77
sumber
2
haha, saya menemukan mereka nyaman :) Tinjauan lebih cepat pada format dan di mana hal-hal dimulai dan berakhir :) masing-masing untuk dirinya sendiri kurasa
slinden77
1
mmm, melihat itu sesuai komentar Anda, terlihat bagus! Tentu saja itu mengacaukan ruang kerja Eclipse saya, tetapi tidak banyak yang diperlukan untuk itu :)
slinden77
2
Oh, beralihlah ke IntelliJ, begitu Anda terbiasa, Eclipse terasa sangat tua;) Di sisi positifnya, Android Studio baru hanyalah IntelliJ dengan beberapa add-ons jadi jika Anda terbiasa dengan Intellij, Android Studio akan membuat Anda merasa seperti di rumah.
Martin Marconcini
2
@ MartínMarconcini akhirnya saya terpaksa beralih ke IntelliJ. Saya sangat menyukainya, tetapi saya membenci kenyataan bahwa tidak mungkin untuk bekerja di 2 proyek secara bersamaan.
slinden77
1
Selamat datang di sisi gelap;) Saya memiliki tiga Android Studio terbuka sekarang dengan 3 proyek berbeda ... tidak yakin apa masalah multi-proyek Anda, tetapi saya dapat meyakinkan Anda bahwa ia bekerja dengan banyak proyek. :)
Martin Marconcini
22

Anda memiliki beberapa opsi

  1. Anda dapat meletakkan bendera di kelas atau aktivitas Anda. Masukkan variabel boolean ke dalam kelas Anda dan lihat bendera ini untuk mengetahui apakah Anda memiliki Receiver terdaftar.

  2. Buat kelas yang memperluas Penerima dan di sana Anda dapat menggunakan:

    1. Pola singleton untuk hanya memiliki satu instance dari kelas ini dalam proyek Anda.

    2. Terapkan metode untuk mengetahui apakah Penerima mendaftar.

chemalarrea
sumber
1
Saya telah melakukan hal yang sama tetapi penerima saya adalah AppWidgetProvider dan saya ingin menerima pesan SCREEN_ON_OFF - tetapi onDisabled () ketika saya batal mendaftarReceiver (ini); - Ini melempar pengecualian.
hB0
opsi gabungan pertama dan kedua, sebuah bendera di kelas receiver, bekerja sangat baik
Gaeburider
dapatkah Anda memberi saya contoh kode karena saya tidak mendapatkan apa yang sebenarnya Anda lakukan ... akan sangat membantu @ chemalarrea
TapanHP
11

Anda harus menggunakan coba / tangkap:

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

Anda dapat melakukannya dengan mudah ....

1) buat variabel boolean ...

private boolean bolBroacastRegistred;

2) Ketika Anda mendaftarkan Penerima Siaran Anda, atur ke TRUE

...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....

3) Di onPause () lakukan itu ...

if (bolBroacastRegistred) {
    this.unregisterReceiver(mReceiver);
    bolBroacastRegistred = false
}

Hanya itu, dan sekarang, Anda tidak akan menerima lebih banyak pesan kesalahan pengecualian pada onPause ().

Tip1: Selalu gunakan unregisterReceiver () di onPause () tidak di onDestroy () Tip2: Jangan lupa untuk mengatur variabel bolBroadcastRegistred ke FALSE ketika menjalankan unregisterReceive ()

Keberhasilan!

Biruel Rick
sumber
6

Jika Anda meletakkan ini di metode onDestroy atau onStop. Saya pikir ketika aktivitas telah dibuat lagi MessageReciver tidak sedang dibuat.

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

}
eloirobe
sumber
3

Saya menggunakan Intent untuk memberi tahu Penerima Siaran tentang instance Handler dari utas Aktivitas utama dan menggunakan Pesan untuk meneruskan pesan ke Aktivitas utama

Saya telah menggunakan mekanisme tersebut untuk memeriksa apakah Siaran Penerima sudah terdaftar atau belum. Kadang-kadang diperlukan ketika Anda mendaftarkan Penerima Siaran Anda secara dinamis dan tidak ingin membuatnya dua kali atau Anda hadir kepada pengguna jika Penerima Siaran sedang berjalan.

Aktifitas utama:

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

.............
}

Penerima siaran:

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

}

}
jarek
sumber
3

Secara pribadi saya menggunakan metode memanggil unregisterReceiver dan menelan pengecualian jika dilempar. Saya setuju ini jelek tapi metode terbaik saat ini disediakan.

Saya telah mengajukan permintaan fitur untuk mendapatkan metode boolean untuk memeriksa apakah penerima terdaftar ditambahkan ke Android API. Harap dukung di sini jika Anda ingin melihatnya ditambahkan: https://code.google.com/p/android/issues/detail?id=73718

ojf
sumber
2

Saya mendapatkan masalah Anda, saya menghadapi masalah yang sama di Aplikasi saya. Saya menelepon registerReceiver () beberapa kali dalam aplikasi.

Solusi sederhana untuk masalah ini adalah memanggil registerReceiver () di Kelas Aplikasi Kustom Anda. Ini akan memastikan bahwa penerima Siaran Anda akan dipanggil hanya satu di seluruh siklus hidup Aplikasi Anda.

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

    }
}
Sameer Ranjan
sumber
1

Ini adalah bagaimana saya melakukannya, ini adalah versi modifikasi dari jawaban yang diberikan oleh ceph3us dan diedit oleh slinden77 (antara lain saya telah menghapus nilai-nilai pengembalian metode yang tidak saya butuhkan):

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

Kemudian pada kelas 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());
    }
}
Víctor Gil
sumber
1

saya meletakkan kode ini di aktivitas orang tua saya

List RegistReceivers = ArrayList baru <> ();

@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);
}
darkwater84
sumber
1

Bagi saya yang berikut ini berfungsi:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}
Benjamin Corben
sumber
0

Inilah yang saya lakukan untuk memeriksa apakah Broadcaster sudah terdaftar, bahkan jika Anda menutup aplikasi Anda (selesai ())

Pertama kali menjalankan aplikasi Anda, kirim siaran terlebih dahulu itu akan mengembalikan benar / salah tergantung pada apakah penyiar Anda masih berjalan atau tidak.

Penyiar saya

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

MainActivity saya

// 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"));
}
janbee
sumber
0

Anda dapat menggunakan Belati untuk membuat referensi penerima itu.

Pertama berikan itu:

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

Kemudian masukkan di mana Anda butuhkan (menggunakan constructoratau bidang injection)

dan cukup berikan registerReceiver.

Juga taruh di try/catchblok juga.

Mahdi-Malv
sumber
-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}
Kamta Sahu
sumber
1
Broadcast yang dipesan benar-benar hal lain yang melihat tautan ini
Vivek Barai
-7

Cukup periksa NullPointerException. Jika penerima tidak ada, maka ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
Kasra
sumber
1
Bagaimana / di mana ini melempar NPE?
DustinB
Sebenarnya tidak ada kesalahan saat gagal. Dengan sedih.
domenukk
2
Sebenarnya, ia melempar IllegalArgumentException
portfoliobuilder