답변:
이 스레드 를 고려하면 API가 API를 직접 제공하는지 잘 모르겠습니다 .
나는 같은 것을 궁금해했다.
내 경우 에는 수신 의도를 처리 한 후 인수로 자신을 전달BroadcastReceiver
하는 호출Context#unregisterReceiver(BroadcastReceiver)
을 구현합니다 .
수신기의있는 작은 기회가있다onReceive(Context, Intent)
가 여러에 등록되어 있기 때문에 방법은, 한 번 이상이라고IntentFilters
에 대한 가능성 생성IllegalArgumentException
에서 던진 존재는Context#unregisterReceiver(BroadcastReceiver)
.필자의 경우을 호출하기 전에 확인할 비공개 동기화 멤버를 저장할 수
Context#unregisterReceiver(BroadcastReceiver)
있지만 API가 체크 메소드를 제공하면 훨씬 깨끗합니다.
수신자가 등록되었는지 확인하는 API 기능이 없습니다. 해결 방법은 코드를try catch block as done below.
try {
//Register or UnRegister your broadcast receiver here
} catch(IllegalArgumentException e) {
e.printStackTrace();
}
null
. 그러나 당신이 지적했듯이, 나는 가고 있습니다 try catch
. 어리석은.
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에 의해 종료 된 경우 작동하지 않습니다. – amin 6 시간 전
@amin-코드의 수명을 참조하십시오 (매니페스트 항목으로 시스템이 등록되지 않음) 등록 수신자 :)
이 솔루션을 사용하고 있습니다
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);
}
}
}
몇 가지 옵션이 있습니다
수업이나 활동에 깃발을 넣을 수 있습니다. 부울 변수를 클래스에 넣고이 플래그를보고 수신자가 등록되어 있는지 확인하십시오.
수신자를 확장하는 클래스를 작성하면 다음을 사용할 수 있습니다.
프로젝트에서이 클래스의 인스턴스가 하나만있는 싱글 톤 패턴.
수신자가 등록되어 있는지 알 수있는 방법을 구현하십시오.
당신은 쉽게 할 수 있습니다 ....
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로 설정하는 것을 잊지 마십시오
성공!
브로드 캐스트 수신자에게 기본 활동 스레드의 핸들러 인스턴스에 대해 알리고 메시지를 기본 활동에 전달하는 데 메시지를 사용했습니다.
브로드 캐스트 수신기가 이미 등록되어 있는지 확인하기 위해 이러한 메커니즘을 사용했습니다. 브로드 캐스트 리시버를 동적으로 등록하고 브로드 캐스트 리시버가 실행중인 경우 브로드 캐스트 리시버를 두 번 만들거나 사용자에게 표시하지 않을 때 필요할 때가 있습니다.
주요 활동:
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();
}
}
.........
}
}
개인적으로 unregisterReceiver를 호출하고 예외가 발생하면 삼키는 방법을 사용합니다. 나는 이것이 추악하지만 현재 제공되는 가장 좋은 방법이라는 데 동의합니다.
수신자가 Android API에 추가되어 등록되어 있는지 확인하기 위해 부울 메소드를 얻는 기능 요청을 제기했습니다. https://code.google.com/p/android/issues/detail?id=73718 추가 된 것을 보려면 여기에서 지원 하십시오
귀하의 문제를 겪습니다. 신청서에 동일한 문제가 있습니다. 응용 프로그램 내에서 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);
}
}
이것은 내가 한 방법입니다. 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());
}
}
이 코드를 부모 활동에 넣었습니다.
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);
}
응용 프로그램을 닫아도 브로드 캐스터가 이미 등록되어 있는지 확인하기 위해 수행 한 작업은 다음과 같습니다 (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"));
}
NullPointerException을 확인하십시오. 수신자가 존재하지 않으면 ...
try{
Intent i = new Intent();
i.setAction("ir.sss.smsREC");
context.sendBroadcast(i);
Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
e.getMessage();
}