จะตรวจสอบว่าผู้รับมีการลงทะเบียนใน Android ได้อย่างไร?


254

ฉันต้องตรวจสอบว่าผู้รับที่ลงทะเบียนของฉันยังคงลงทะเบียนอยู่หรือไม่ถ้าฉันจะตรวจสอบวิธีการใด ๆ ได้บ้าง?


คำตอบ:


68

ฉันไม่แน่ใจว่า API ให้ API โดยตรงหากคุณพิจารณาหัวข้อนี้ :

ฉันสงสัยในสิ่งเดียวกัน
ในกรณีของฉันฉันมีการBroadcastReceiverใช้งานที่โทร Context#unregisterReceiver(BroadcastReceiver)ผ่านตัวเองเป็นอาร์กิวเมนต์หลังจากจัดการกับเจตนาที่ได้รับ
มีโอกาสเล็ก ๆ ที่ผู้รับเป็นonReceive(Context, Intent)วิธีการที่เรียกว่ามากกว่าหนึ่งครั้งเพราะมันมีการลงทะเบียนที่มีหลายIntentFiltersสร้างศักยภาพในการที่จะถูกโยนลงมาจากIllegalArgumentExceptionContext#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
นั่นเป็นคนเกียจคร้าน ... :(
Sander Versluys

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 Studio เมื่อฉันพยายามที่จะขยาย BroadcastReceiver มันบ่นและต้องการแทนที่ onReceive โชคดีที่ในกรณีของฉันฉันต้องการขยาย ScreenReceiver ซึ่งทำงานอย่างที่ ceph3us อธิบายตรงนี้
MarkJoel60

สิ่งนี้ไม่หรูหราอย่างนั้นเพราะคุณต้องจำไว้ว่าให้ตั้งค่าสถานะ isRegistered หลังจากที่คุณลงทะเบียน
ชิงทรัพย์แรบไบ

ใช่แม้ว่าคุณจะสามารถลบบรรทัดนี้ออกจากส่วน "ในรหัส" myReceiver.isRegistered = true;
Stealth Rabbi

นี่ควรจะเป็นคลาสนามธรรมหรือไม่? การขยาย BroadcastReceiver คุณต้องใช้วิธีการ onReceive
York Yang

@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
อืมมมมองว่ามันเป็นความคิดเห็นของคุณดูดี! ofcourse มันเมาขึ้นพื้นที่ทำงานคราสของฉัน แต่ไม่มากเป็นสิ่งจำเป็นสำหรับ :) ว่า
slinden77

2
โอ้สลับไปที่ IntelliJ เมื่อคุณคุ้นเคยกับมันแล้ว Eclipse รู้สึกเก่ามาก) ด้านบวก Android Studio ใหม่เป็นเพียง IntelliJ ที่มีส่วนเสริมเล็กน้อยดังนั้นหากคุณคุ้นเคยกับ Intellij แล้ว Android Studio จะ ทำให้คุณรู้สึกเหมือนอยู่บ้าน
Martin Marconcini

2
@ MartínMarconciniในที่สุดฉันก็ถูกบังคับให้เปลี่ยนไปใช้ IntelliJ ฉันชอบมันมาก แต่ฉันดูถูกความจริงที่ว่ามันเป็นไปไม่ได้ที่จะทำงานใน 2 โครงการพร้อมกัน
slinden77

1
ยินดีต้อนรับสู่ด้านมืด;) ฉันมีสาม Android Studio ที่เปิดในขณะนี้ด้วย 3 โครงการที่แตกต่างกัน ... ไม่แน่ใจว่าปัญหาหลายโครงการของคุณคืออะไร แต่ฉันสามารถมั่นใจได้ว่ามันทำงานได้กับหลายโครงการ :)
Martin Marconcini

22

คุณมีหลายทางเลือก

  1. คุณสามารถใส่ธงลงในชั้นเรียนหรือกิจกรรมของคุณ ใส่ตัวแปรบูลีนลงในชั้นเรียนของคุณแล้วดูที่ธงนี้เพื่อทราบว่าคุณได้ลงทะเบียนตัวรับสัญญาณแล้วหรือยัง

  2. สร้างคลาสที่ขยายตัวรับและคุณสามารถใช้:

    1. รูปแบบซิงเกิลสำหรับมีเพียงอินสแตนซ์เดียวของคลาสนี้ในโครงการของคุณ

    2. ใช้วิธีการเพื่อทราบว่าผู้รับลงทะเบียนหรือไม่


1
ฉันได้ทำแบบเดียวกัน แต่ผู้รับของฉันคือ AppWidgetProvider และฉันต้องการรับข้อความ SCREEN_ON_OFF - แต่ onDisabled () เมื่อฉัน unregisterReceiver (นี่); - มันมีข้อผิดพลาด
hB0

รวมตัวเลือกแรกและตัวที่สองซึ่งเป็นธงในระดับผู้รับทำงานได้ดีมาก
Gaeburider

คุณสามารถให้ฉันเป็นตัวอย่างโค้ด im ไม่ได้รับสิ่งที่ ur ว่าจะทำ ... b @chemalarrea ช่วยเหลือที่ดี
TapanHP

11

คุณต้องใช้ลอง / จับ:

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

7

คุณทำได้ง่ายๆ ....

1) สร้างตัวแปรบูลีน ...

private boolean bolBroacastRegistred;

2) เมื่อคุณลงทะเบียน Broadcast Receiver ให้ตั้งเป็น TRUE

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

3) ใน onPause () ทำมัน ...

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

แค่นี้และตอนนี้คุณจะไม่ได้รับข้อความแสดงข้อผิดพลาดเพิ่มเติมอีกใน onPause ()

Tip1: ใช้ unregisterReceiver () ใน onPause () ไม่ได้อยู่ใน onDestroy () Tip2: อย่าลืมตั้งค่าตัวแปร bolBroadcastRegistred เป็น FALSE เมื่อเรียกใช้ unregisterReceive ()

ที่ประสบความสำเร็จ!


6

หากคุณวางไว้บนวิธีการทำลายหรือวิธีการหยุด ฉันคิดว่าเมื่อกิจกรรมถูกสร้างขึ้นอีกครั้ง MessageReciver ไม่ได้ถูกสร้างขึ้น

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

}

3

ฉันใช้ Intent เพื่อให้ Broadcast Receiver ทราบเกี่ยวกับอินสแตนซ์ตัวจัดการของเธรดกิจกรรมหลักและใช้ข้อความเพื่อส่งข้อความไปยังกิจกรรมหลัก

ฉันใช้กลไกดังกล่าวเพื่อตรวจสอบว่า Broadcast Receiver ได้รับการลงทะเบียนแล้วหรือไม่ บางครั้งมีความจำเป็นเมื่อคุณลงทะเบียน Broadcast Receiver ของคุณแบบไดนามิกและไม่ต้องการที่จะทำให้มันสองครั้งหรือคุณนำเสนอให้กับผู้ใช้ถ้า Broadcast Receiver ทำงาน

กิจกรรมหลัก:

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 () ใน Custom Application Class ของคุณ สิ่งนี้จะช่วยให้มั่นใจได้ว่าตัวรับสัญญาณออกอากาศของคุณจะถูกเรียกเพียงครั้งเดียวในรอบการใช้งานทั้งหมดของคุณ

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

ฉันใส่รหัสนี้ในกิจกรรมหลักของฉัน

List registerReceivers = 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

นี่คือสิ่งที่ฉันทำเพื่อตรวจสอบว่าผู้ลงโฆษณาได้ลงทะเบียนแล้วแม้ว่าคุณจะปิดแอปพลิเคชันของคุณ (เสร็จสิ้น ())

Firsttime ใช้แอปพลิเคชั่นของคุณส่งการออกอากาศก่อนที่มันจะคืนค่าจริง / เท็จขึ้นอยู่กับว่าผู้ประกาศของคุณยังคงทำงานอยู่หรือไม่

โฆษกของฉัน

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 ของฉัน

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

คุณสามารถใช้กริชเพื่อสร้างการอ้างอิงของผู้รับนั้น

ก่อนอื่นให้มัน:

@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

มันจะไม่โยนข้อผิดพลาดใด ๆ เมื่อมันไม่สำเร็จ เศร้า.
domenukk

2
ที่จริงแล้วมันจะโยน IllegalArgumentException
portfoliobuilder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.