以编程方式注册广播接收器

165
我希望了解以编程方式注册广播接收器的最佳实践/方法。我想根据用户选择注册特定的接收器。
由于注册是通过清单文件完成的,因此我想知道是否有适当的方法在代码中实现这一点。

2
CoderzPassion Broadcast Receiver 是有史以来最详细的教程。 - karanatwal.github.io
请参考此链接:https://dev59.com/U2Uo5IYBdhLWcg3w3yqi#44881551 - user8203509
10个回答

284

你可以在onCreate方法中像这样注册一个接收器:

private BroadcastReceiver receiver;

@Override
public void onCreate(Bundle savedInstanceState){

  // your oncreate code should be

  IntentFilter filter = new IntentFilter();
  filter.addAction("SOME_ACTION");
  filter.addAction("SOME_OTHER_ACTION");

  receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      //do something based on the intent's action
    }
  };
     registerReceiver(receiver, filter);
}

记得在onDestroy方法中运行此代码:

 @Override
 protected void onDestroy() {
  if (receiver != null) {
   unregisterReceiver(receiver);
   receiver = null;
  }
  super.onDestroy();
 }

19
谢谢,这个方法很有效。为了发送广播,我使用了以下代码:Intent i = new Intent("SOME_ACTION"); sendBroadcast(i); - Ben Clayton
7
为什么不写在简历和开始时? - Syed Raza Mehdi
如果我不取消注册广播接收器会发生什么? 即使重新启动后,广播接收器是否仍然保持注册状态? - Jaydev
6
不能保证onDestroy()一定会被调用,因此可能会导致内存泄漏。更好的做法是在onStart()/onStop()中注册/取消注册。 - Neria Nachum
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),100,i,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);待处理意图 pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),100,i,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mohamed salem
显示剩余3条评论

72

有一个重要的点,人们经常遗忘提及 Broadcast Receiver 的生命周期。通过程序注册和在 AndroidManifest.xml 注册的区别在于,在清单文件中,它不依赖于应用程序的生命周期。而当以编程方式进行注册时,则会依赖于应用程序的生命周期。这意味着,如果您在 AndroidManifest.xml 中注册,即使您的应用程序没有运行,也可以捕获广播的意图。

编辑:截至 Android 3.1,上述注释不再适用,如果相应的应用程序从未被用户启动或者用户通过 Android 菜单(在 Manage → Application 中)明确停止了该应用程序,则 Android 系统默认排除所有接收器接收意图。https://developer.android.com/about/versions/android-3.1.html

这是一个附加的安全功能,因为用户可以确信只有他启动的应用程序将接收广播意图。

因此,可以理解为在 onCreate() 中以编程方式注册的接收器与从 Android 3.1 开始在 AndroidManifest.xml 中声明的接收器具有相同的效果。


1
这是一个好笔记。我实际上正在看一本关于Android的书,想知道为什么会同时实现两种广播实现方法。在我看来,这似乎是为了向后兼容性。但我不确定。 - Neon Warge
1
你认为这个修改是真的吗?我的意思是最后一句话。Android可能随时终止你的应用程序,这将导致你通过编程方式注册的接收器不再工作,但清单注册的仍然可以工作。 - JacksOnF1re

68

看起来您想要控制在清单中发布的组件是否活动,而不是在运行时通过Context.registerReceiver()动态注册接收器。

如果是这样的话,您可以使用PackageManager.setComponentEnabledSetting()方法来控制这些组件是否活动:

http://developer.android.com/reference/android/content/pm/PackageManager.html#setComponentEnabledSetting(android.content.ComponentName, int, int)

请注意,如果您只对在运行时接收广播感兴趣,最好使用registerReceiver()方法。接收器组件主要用于确保每次发送广播时都启动您的应用程序。


1
聪明!你直接抓住了我的意思。非常感谢你。 - CoolStraw
不错 - 我不知道你可以这样做 :) - Chris Noldus
我可以在Java代码中注册小部件而不是在Android清单中注册吗? - Ankit Srivastava
1
@hackbod 你知道怎么在自定义接收器中添加元数据标签吗?我需要添加一个在androidmanifest.xml中使用的元数据标签。 - Zala Janaksinh
1
到目前为止最好的教程:http://coderzpassion.com/implement-broadcastreceiver-android/,并以简单易懂的语言解释。 - Jagjit Singh

44
在Activity/Fragment中可以像这样定义一个广播接收器:

Define a broadcast receiver anywhere in Activity/Fragment like this:

mReceiver = new BroadcastReceiver() {
 @Override
 public void onReceive(Context context, Intent intent) {
     Log.d(TAG," onRecieve"); //do something with intent
   }
 };

onCreate()中定义IntentFilter

mIntentFilter=new IntentFilter("action_name");

现在在onResume()中注册BroadcastReciever,在onPause()中取消注册 [因为如果活动已暂停,广播就没有用了]。

@Override
protected void onResume() {
     super.onResume();
     registerReceiver(mReceiver, mIntentFilter);
}

@Override
protected void onPause() {
    if(mReceiver != null) {
            unregisterReceiver(mReceiver);
            mReceiver = null;
    }
    super.onPause();
}

如果需要详细的教程,请参考广播接收器 - 两种实现方式


到目前为止我发现的最好的例子!谢谢! - Ayush Goyal
1
@SohailAziz 这个链接提供了一个很好的答案。你能在你的回答中加入链接的上下文吗?这样,即使链接失效,你的回答仍然相关。 - iRuth
在我个人看来,广播应该像你建议的那样在onResume和onPause中注册,但有些人说它必须在onCreate和onDestroy中注册,你能解释一下两者的优缺点吗? - Syed Raza Mehdi
2
@SyedRazaMehdi 如果广播用于更新UI [这在大多数情况下都是如此],则应在onResume中注册它,并在onPause中注销,否则广播将无效。 - SohailAziz
谢谢。这是最好的答案。 - Saeid Z
如果您在活动中使用广播,则仍然可以在onCreate()中注册并在onDestory()中注销以更新UI,因为视图在onPause()后不会被销毁。对于片段,可以在onViewCreated()和onDestroyView()中进行操作。但我同意,onPause()和onResume()是接收用于UI渲染的广播的最安全的位置。 - Tamim Attafi

4
package com.example.broadcastreceiver;


import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

   UserDefinedBroadcastReceiver broadCastReceiver = new UserDefinedBroadcastReceiver();

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
   }

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }

   /**
    * This method enables the Broadcast receiver for
    * "android.intent.action.TIME_TICK" intent. This intent get
    * broadcasted every minute.
    *
    * @param view
    */
   public void registerBroadcastReceiver(View view) {

      this.registerReceiver(broadCastReceiver, new IntentFilter(
            "android.intent.action.TIME_TICK"));
      Toast.makeText(this, "Registered broadcast receiver", Toast.LENGTH_SHORT)
            .show();
   }

   /**
    * This method disables the Broadcast receiver
    *
    * @param view
    */
   public void unregisterBroadcastReceiver(View view) {

      this.unregisterReceiver(broadCastReceiver);

      Toast.makeText(this, "unregistered broadcst receiver", Toast.LENGTH_SHORT)
            .show();
   }
}

1
你能否向OP解释为什么这是最佳实践? - Martin Prikryl
1
他们不解释,总是贴代码,因为这样更好,你懂的。-讽刺 - Neon Warge

3

两种选择

1) 如果您想在Activity可见时才读取广播,则在onStart()中调用registerReceiver(...),并在onStop()中调用unregisterReceiver(...)

2) 如果您想即使Activity在后台也要读取广播,则在onCreate(...)中调用registerReceiver(...),并在onDestroy()中调用unregisterReceiver(...)

奖励:

如果您懒得写重复的注册和注销BroadcastReceiver的样板代码,那么可以:

  1. 创建一个抽象的Activity
  2. 在Activity中编写样板代码
  3. 将实现留作抽象方法

以下是代码片段:

抽象Activity

public abstract class BasicActivity extends AppCompatActivity {

    private BroadcastReceiver broadcastReceiver;
    private IntentFilter filter;
    private static final String TAG = "BasicActivity";

    /**********************************************************************
    *                   Boilerplate code
    **********************************************************************/

    @Override
    public void onCreate(Bundle sis){
        super.onCreate(sis);
        broadcastReceiver = getBroadcastReceiver();
        filter = getFilter();
    }

    @Override
    public void onStart(){
        super.onStart();
        register();
    }

    @Override
    public void onStop(){
        super.onStop();
        unregister();
    }

    private void register(){
        registerReceiver(broadcastReceiver,filter);
    }

    private void unregister(){
        unregisterReceiver(broadcastReceiver);
    }

    /**********************************************************************
    *                   Abstract methods
    **********************************************************************/

    public abstract BroadcastReceiver getBroadcastReceiver();

    public abstract IntentFilter getFilter();

}

使用这种方法,您可以编写更多的样板代码,例如编写常见的动画,绑定到服务等。

查看完整代码:

在此处


2

关于 LocalBroadcastManager

   Intent intent = new Intent("any.action.string");
   LocalBroadcastManager.getInstance(context).
                                sendBroadcast(intent);

并在onResume中注册

LocalBroadcastManager.getInstance(
                    ActivityName.this).registerReceiver(chatCountBroadcastReceiver, filter);

并在 onStop 中取消注册它。

LocalBroadcastManager.getInstance(
                ActivityName.this).unregisterReceiver(chatCountBroadcastReceiver);

并且接收它...
mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("mBroadcastReceiver", "onReceive");
        }
    };

IntentFilter是什么

 new IntentFilter("any.action.string")

2

1
我尝试调用 context.registerReceiver 但它没有被调用,你能否看一下这个问题:https://dev59.com/ImrWa4cB1Zd3GeqP_XvI - Hunt

2

在注册接收器时,最好始终提供权限,否则您将接收到发送匹配意图的任何应用程序。这可能会使恶意应用程序广播到您的接收器。


0

创建广播接收器

[BroadcastReceiver(Enabled = true, Exported = false)]

public class BCReceiver : BroadcastReceiver
{

    BCReceiver receiver;

    public override void OnReceive(Context context, Intent intent)
    {
        //Do something here
    }
}

从您的活动中添加此代码:

LocalBroadcastManager.getInstance(ApplicationContext)
    .registerReceiver(receiver, filter);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接