レシーバーがAndroidに登録されているかどうかを確認するにはどうすればよいですか?


回答:


68

このスレッドを検討した場合、APIが直接APIを提供するかどうかはわかりません。

私も同じことを考えていました。
私の場合、受け取ったインテントを処理した後、引数としてそれ自体を渡すBroadcastReceiverことを呼び出す実装があります Context#unregisterReceiver(BroadcastReceiver)
受信者のことを小さなチャンスがありonReceive(Context, Intent)、それが複数に登録されているので、この方法は、複数回呼び出されたIntentFiltersの潜在的な作成、IllegalArgumentExceptionからスローされるがContext#unregisterReceiver(BroadcastReceiver)

私の場合、呼び出す前にチェックするプライベート同期メンバーを保存できContext#unregisterReceiver(BroadcastReceiver)ますが、APIがcheckメソッドを提供した方がずっときれいです。


313

レシーバーが登録されているかどうかを確認するAPI関数はありません。回避策は、コードをtry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
それは残念なことです... :(
Sander Versluys、2011年

4
おかしいのは、registerReceiver(mReceiver、filter1);のBroadcastReceiverへのこの呼び出しのエラーをキャッチしないことです。
JPM 2012年

1
@JPMはい、そうです。私は自分のレシーバーのインスタンスを保存し、それが登録されていない場合は登録を解除することを確認しましたnull。しかし、あなたが指摘したように、私は一緒に行きtry catchます。ばかげている。

9
そのためのAPIを作成しないためにAndroidに反対票を投じてください。実用的なソリューションを提供するための+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フラグを設定することを忘れないようにする必要があるため、これは実際にはそれほどエレガントではありません。–ステルスラビ

-フラグを登録および設定するための「よりエレガントな方法」がレシーバーに追加されました

これは、デバイスを再起動した場合、またはアプリがOSによって強制終了された場合は機能しません。–アミン6時間前

@amin-コード内の有効期間を確認(マニフェストエントリによって登録されたシステムではない)登録済みレシーバー


2
これは本当にエレガントなソリューションです。FWIW、Android StudioでBroadcastReceiverを拡張しようとすると、エラーが発生し、onReceiveのオーバーライドが必要になります。幸い、私の場合、ceph3usがここで説明するとおりに動作するScreenReceiverを拡張する必要がありました。
MarkJoel60

登録後にisRegisteredフラグを設定することを忘れないようにする必要があるため、これは実際にはそれほどエレガントではありません。
Stealth Rabbi

はい。ただし、「コード内」セクションからこの行を削除できます。myReceiver.isRegistered = true;
Stealth Rabbi

これは抽象クラスであってはなりませんか?BroadcastReceiverを拡張するには、onReceiveメソッドを実装する必要があります。
ニューヨークヤン

@YorkYangがクラスの下部に情報を追加しました
ceph3us 2017

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はくつろいでください。
Martin Marconcini、2013年

2
@MartínMarconciniようやくついに私はIntelliJに切り替えることを余儀なくされました。私はそれがとても好きですが、同時に2つのプロジェクトで作業することは不可能であるという事実を軽視します。
slinden77

1
ダークサイドへようこそ;)現在、3つのAndroid Studioを3つの異なるプロジェクトで開いています。マルチプロジェクトの問題が何であるかはわかりませんが、複数のプロジェクトで機能することを保証できます。:)
Martin Marconcini

22

いくつかのオプションがあります

  1. クラスやアクティビティにフラグを付けることができます。ブール変数をクラスに入れ、このフラグを見て、Receiverが登録されているかどうかを確認します。

  2. レシーバーを拡張するクラスを作成し、そこで使用できます。

    1. プロジェクトのこのクラスのインスタンスが1つしかないシングルトンパターン。

    2. レシーバーが登録されているかどうかを知るためのメソッドを実装します。


1
私は同じことをしましたが、私のレシーバーはAppWidgetProviderであり、SCREEN_ON_OFFメッセージを受信したいのですが、unregisterReceiver(this);のときはonDisabled()です。-例外をスローします。
hB0 2013

レシーバークラスのフラグである、1番目と2番目のオプションの組み合わせが大きく機能する
Gaeburider

urが正確に何をしているのかわからないので、コード例を教えてもらえますか?@chemalarreaの大きな助けになります
TapanHP

11

try / catchを使用する必要があります。

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

7

簡単にできます。

1)ブール変数を作成します...

private boolean bolBroacastRegistred;

2)ブロードキャストレシーバーを登録するときに、TRUEに設定します。

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

3)onPause()でそれを行います...

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

それだけで、今では、onPause()でこれ以上の例外エラーメッセージを受け取ることはありません。

ヒント1:onDestroy()ではなくonPause()で常にunregisterReceiver()を使用しますヒント2:unregisterReceive()を実行するときは、bolBroadcastRegistred変数をFALSEに設定することを忘れないでください

成功!


6

これをonDestroyまたはonStopメソッドに配置した場合。アクティビティが再度作成されたとき、MessageReciverは作成されていなかったと思います。

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

}

3

Intentを使用してブロードキャストレシーバーにメインアクティビティスレッドのハンドラインスタンスを通知し、メッセージを使用してメッセージをメインアクティビティに渡しました

そのようなメカニズムを使用して、ブロードキャストレシーバーがすでに登録されているかどうかを確認しました。ブロードキャストレシーバーを動的に登録し、それを2度作成したくない場合や、ブロードキャストレシーバーが実行されている場合にユーザーに提示するときに必要になることがあります。

主な活動:

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

個人的には、unregisterReceiverを呼び出し、例外がスローされた場合にそれを飲み込む方法を使用しています。これは醜いですが、現在提供されている最善の方法です。

Android APIに追加されたレシーバーが登録されているかどうかを確認するためのブールメソッドを取得する機能リクエストを発生させました。追加を確認したい場合は、こちらでサポートしてください:https : //code.google.com/p/android/issues/detail?id=73718


2

私はあなたの問題を得ます、私は私のアプリケーションで同じ問題に直面しました。アプリケーション内でregisterReceiver()を複数回呼び出していました。

この問題の簡単な解決策は、カスタムアプリケーションクラスでregisterReceiver()を呼び出すことです。これにより、ブロードキャストレシーバーがアプリケーションライフサイクル全体で1つだけ呼び出されるようになります。

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

次に、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());
    }
}

1

このコードを親アクティビティに配置しました

リストregisteredReceivers = new 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

アプリケーションを終了した場合でも、Broadcasterがすでに登録されているかどうかを確認するために、次のことを行いました(finish())

Firstimeがアプリケーションを実行している場合、最初にブロードキャストを送信します。true/ falseが返されるかどうかは、ブロードキャスターがまだ実行中であるかどうかによって異なります。

私の放送局

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をスローしますか?
DustinB 2014年

実際には、失敗してもエラーはスローされません。悲しいことに。
domenukk 2014年

2
実際には、IllegalArgumentExceptionがスローされます
ポートフォリオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.