Alıcının Android'de kayıtlı olup olmadığını nasıl kontrol edebilirim?


Yanıtlar:


68

Bu iş parçacığı düşünüyorsanız, API doğrudan bir API sağlar emin değilim :

Aynı şeyi merak ediyordum.
Benim durumumda , aldığı Niyeti ele aldıktan sonra kendisini argüman olarak geçirmeyi BroadcastReceiverçağıran bir uygulamam var Context#unregisterReceiver(BroadcastReceiver).
Alıcının onReceive(Context, Intent)yönteminin birden çok kez kaydedildiğinden, birden fazla atılma IntentFiltersolasılığı yarattığından, birden çok kez çağrılma olasılığı düşüktür .IllegalArgumentExceptionContext#unregisterReceiver(BroadcastReceiver)

Benim durumumda, aramadan önce kontrol etmek için özel bir senkronize üye depolayabilirim Context#unregisterReceiver(BroadcastReceiver), ancak API bir kontrol yöntemi sağlamışsa çok daha temiz olurdu.


313

Bir alıcının kayıtlı olup olmadığını kontrol etmek için API işlevi yoktur. Çözüm, kodunuzu birtry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
bu bir serseri ... :(
Sander Versluys

4
Komik olan şey, registerReceiver (mReceiver, filter1) için BroadcastReceiver çağrısı için hatayı yakalamamasıdır;
JPM

1
@JPM Evet öyle. Alıcımın bir örneğini saklayacak ve eğer kayıtlı değilse kayıt sicilini kontrol edecektim null. Ama işaret ettiğin gibi, ben de gidiyorum try catch. Saçma.

9
Bunun için bir API oluşturmadığı için Android'e oy verin. Çalışan bir çözüm sağladığınız için +1 +1 :)
Denys Vitali

1
Daha iyi olan ne? Bunu veya boole değişkenini bayrak olarak mı kullanıyorsunuz?
DAVIDBALAS1

34

en basit çözüm

alıcıda:

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

kodda:

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

reklam 1

- yanıt olarak:

Bu gerçekten zarif değil, çünkü kayıt olduktan sonra isRegistered bayrağını ayarlamayı hatırlamanız gerekiyor. - Gizli Rabbi

- "daha zarif bir şekilde" alıcı kaydetmek ve bayrak ayarlamak için yöntem eklendi

Bu, cihazı yeniden başlatırsanız veya uygulamanız işletim sistemi tarafından öldürülürse çalışmaz. - amin 6 saat önce

@amin - kodun kullanım ömrüne bakın (manifest girişi ile kayıtlı sistem değil) kayıtlı alıcı :)


2
Bu gerçekten zarif bir çözüm. FWIW, Android Studio'da BroadcastReceiver'ı genişletmeye çalıştığımda şikayet ediyor ve onReceive'ın geçersiz kılınmasını istiyor. Neyse ki, benim durumumda, tam olarak ceph3us'un burada açıkladığı şekilde çalışan ScreenReceiver'ı uzatmam gerekiyordu.
MarkJoel60

Bu gerçekten zarif değil çünkü kaydolduktan sonra isRegistered bayrağını ayarlamayı hatırlamanız gerekiyor.
Stealth Rabbi

Evet, ancak bu satırı "kod içinde" bölümünüzden kaldırabilirsiniz. myReceiver.isRegistered = true;
Stealth Haham

bu soyut bir sınıf olmamalı mı? BroadcastReceiver'ın genişletilmesi, onReceive yöntemini uygulamanızı gerektirir.
York Yang

@YorkYang en altta sınıfta bilgi ekledi
ceph3us

27

Bu çözümü kullanıyorum

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
haha, onları uygun buluyorum :) Biçimi ve şeyler başlar ve nerede biter hızlı bakış :) her biri kendi başına sanırım
slinden77

1
mmm, yorumunuza göre, iyi görünüyor! Tabii ki benim Eclipse çalışma alanımı berbat, ama bunun için çok fazla gerekli :)
slinden77

2
Oh, IntelliJ'e geçin, alıştıktan sonra Eclipse gerçekten eski hissediyor;) Artı tarafta, yeni Android Studio sadece birkaç eklentiye sahip bir IntelliJ'dir, bu nedenle Intellij'e alışkınsanız, Android Studio kendinizi evinizde hissetmenizi sağlar.
Martin Marconcini

2
@ MartínMarconcini sonunda IntelliJ'e geçmek zorunda kaldım. Çok beğendim, ama aynı anda 2 projede çalışmanın imkansız olduğunu düşünüyorum.
slinden77

1
Karanlık tarafa hoş geldiniz;) Şu anda 3 farklı projeyle açık üç Android Studio'm var… çoklu proje sorununun ne olduğundan emin değilim, ancak birden fazla projeyle çalıştığından emin olabilirim. :)
Martin Marconcini

22

Birkaç seçeneğiniz var

  1. Sınıfınıza veya etkinliğinize bir bayrak koyabilirsiniz. Sınıfınıza bir boole değişkeni koyun ve Alıcının kayıtlı olup olmadığını öğrenmek için bu bayrağa bakın.

  2. Alıcıyı genişleten bir sınıf oluşturun ve orada şunları kullanabilirsiniz:

    1. Projenizde bu sınıfın yalnızca bir örneği için tekli desen var.

    2. Alıcının kayıt olup olmadığını bilmek için yöntemler uygulayın.


1
Ben de aynı şeyi yaptım ama benim alıcı AppWidgetProvider ve ben SCREEN_ON_OFF mesajları almak istiyorum - ama unregisterReceiver (this); - istisna atıyor.
hB0

birinci ve ikinci seçenek, alıcı sınıfında bir bayrak, harika çalışıyor
Gaeburider

Bana tam olarak ne yaptığını alamadım gibi bir kod örneği verebilir misin ... b büyük yardım @chemalarrea
TapanHP

11

Try / catch kullanmalısınız:

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

7

Kolayca yapabilirsiniz ....

1) bir boole değişkeni oluşturun ...

private boolean bolBroacastRegistred;

2) Yayın Alıcınızı kaydettirdiğinizde, TRUE olarak ayarlayın

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

3) onPause () içinde yapın ...

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

Sadece ve şimdi, onPause () üzerinde daha fazla istisna hata mesajı almayacaksınız.

İpucu 1: onDestroy'da olmayan onPause () öğesinde daima unregisterReceiver () öğesini kullanın.

Başarı!


6

Bunu onDestroy veya onStop yöntemine koyarsanız. Etkinlik yeniden oluşturulduğunda MessageReciver'ın oluşturulmadığını düşünüyorum.

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

}

3

Yayın Alıcının ana Etkinlik iş parçacığının İşleyici örneği hakkında bilgilendirmesine izin vermek amacıyla kullandım ve Ana etkinliğe ileti iletmek için İleti kullandım

Yayın Alıcının zaten kayıtlı olup olmadığını kontrol etmek için böyle bir mekanizma kullandım. Bazen Yayın Alıcınızı dinamik olarak kaydettirmeniz ve iki kez yapmak istemediğiniz veya Yayın Alıcısı çalışıyorsa kullanıcıya sunmanız gerekebilir.

Ana aktivite:

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

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

Yayın alıcı:

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

Şahsen ben unregisterReceiver çağırma ve atılırsa istisna yutma yöntemini kullanın. Bu çirkin ama şu anda sağlanan en iyi yöntem katılıyorum.

Android API'ye eklenen bir alıcının kayıtlı olup olmadığını kontrol etmek için bir boole yöntemi elde etmek için bir özellik isteği yükselttim. Eklendiğini görmek istiyorsanız lütfen buradan destekleyin: https://code.google.com/p/android/issues/detail?id=73718


2

Sorununuzu alıyorum, Uygulamamda da aynı sorunla karşılaştım. Uygulama içinde birden fazla kez registerReceiver () çağırıyordu.

Bu soruna basit bir çözüm, Özel Uygulama Sınıfınızdaki registerReceiver () yöntemini çağırmaktır. Bu, Yayın alıcınızın tüm Uygulama yaşam döngünüzde yalnızca bir tane olarak çağrılmasını sağlayacaktır.

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

Ben böyle yaptım, ceph3us tarafından verilen ve slinden77 tarafından düzenlenen cevabın değiştirilmiş bir versiyonudur (diğer şeylerin yanı sıra, ihtiyacım olmayan yöntemlerin dönüş değerlerini kaldırdım):

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

Sonra bir Activity sınıfında:

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

bu kodu ana faaliyetime koydum

RegistrationReceivers = new ArrayList <> (); listesi

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

1

Benim için aşağıdakiler işe yaradı:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}

0

Uygulamanızı kapatsanız bile Broadcaster'ın kayıtlı olup olmadığını kontrol etmek için yaptığım şey (bitirmek ())

Uygulamanızı ilk kez çalıştırdığınızda, önce yayın gönderin doğru / yanlış döndürür Yayıncınızın hala çalışıp çalışmadığına bağlıdır.

Yayıncım

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'm

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

Bu alıcının referansını oluşturmak için Hançeri kullanabilirsiniz .

İlk önce sağlayın:

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

Sonra ihtiyacınız olan yere enjekte edin ( constructorveya alan kullanarak injection)

ve basitçe şuraya aktarın registerReceiver.

Ayrıca try/catchbloğa da koy .



-7

Sadece NullPointerException'ı kontrol edin. Alıcı yoksa, o zaman ...

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

1
Bu bir NPE'yi nasıl / nereye atıyor?
DustinB

Aslında başarısız olduğunda herhangi bir hata atmaz. Ne yazık ki.
domenukk

2
Aslında, IllegalArgumentException oluşturuyor
portföy oluşturucu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.