如何使用LocalBroadcastManager?

480
如何使用/定位在Google文档服务广播文档中描述的LocalBroadcastManager
我尝试谷歌搜索,但没有可用的代码起点?
文档说如果我想在我的应用程序进程内部进行广播,则应该使用它,但是我不知道要查找哪里。
有任何帮助/评论吗?
更新:我知道如何使用广播,但不知道如何在项目中获得LocalBroadcastManager

Waqas,你在清单中注册了接收器吗?如果是,请告诉我如何操作? - Mudassir
2
我认为您不需要在清单中注册接收器来接收此类广播,因为如果这样做,那么该接收器也将监听全局广播。 - waqaslam
3
是的。这意味着我必须按照下面的答案中给出的代码进行操作:LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("custom-event-name")); - Mudassir
2
LocalBroadcastManager已被弃用。我用更好的EventBus库替换了它,个人认为这样更好。 - Kris B
13个回答

888

我还是会回答这个问题,以防有人需要。

ReceiverActivity.java

一个观察名为"custom-event-name"的事件通知的活动。

@Override
public void onCreate(Bundle savedInstanceState) {

  ...

  // Register to receive messages.
  // We are registering an observer (mMessageReceiver) to receive Intents
  // with actions named "custom-event-name".
  LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
      new IntentFilter("custom-event-name"));
}

// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get extra data included in the Intent
    String message = intent.getStringExtra("message");
    Log.d("receiver", "Got message: " + message);
  }
};

@Override
protected void onDestroy() {
  // Unregister since the activity is about to be closed.
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
  super.onDestroy();
}

SenderActivity.java

发送/广播通知的第二个活动。

@Override
public void onCreate(Bundle savedInstanceState) {

  ...

  // Every time a button is clicked, we want to broadcast a notification.
  findViewById(R.id.button_send).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      sendMessage();
    }
  });
}

// Send an Intent with an action named "custom-event-name". The Intent sent should 
// be received by the ReceiverActivity.
private void sendMessage() {
  Log.d("sender", "Broadcasting message");
  Intent intent = new Intent("custom-event-name");
  // You can also include some extra data.
  intent.putExtra("message", "This is my message!");
  LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
使用上述代码,每当单击按钮 R.id.button_send 时,就会广播一个 Intent,并由 ReceiverActivity 中的 mMessageReceiver 接收。

调试输出应该如下所示:

01-16 10:35:42.413: D/sender(356): Broadcasting message
01-16 10:35:42.421: D/receiver(356): Got message: This is my message! 

7
谢谢,我已经让它正常工作了。但我面临的问题是获取LocalBroadcastManager类。由于它是一个支持包类,所以在没有添加Android工具的兼容库之前,我不能在普通包中使用它。一旦它被添加,一切都很顺利。无论如何,感谢您的回答。 - waqaslam
199
请注意,onDestroy() 不能保证被调用!因此,您必须使用onPause()(因为它是唯一能够保证调用的方法)和onResume()(因为它对应于onPause())。请注意不要改变原文意思。 - 18446744073709551615
5
注意,Google文档现在关于onPause()之后Activity的状态:在HONEYCOMB版本之前,应用程序处于可杀死状态;从Honeycomb开始,直到其onStop()返回之前,应用程序不处于可杀死状态。 - 18446744073709551615
63
onDestroy() 没问题。它不被调用的情况是当应用被杀死时,如果在那种情况下您没有注销,也没有关系,因为即使注册接收器的列表也不会幸存下来。 - zapl
4
@Selvin 我希望你知道可以将BroadcastReceiver设为弱引用并使其在所接收的Activity中取消注册,如果它被孤立了。你不需要在onPause中取消注册,只要不使用BroadcastReceiver来保持Activity在RAM中存活即可,onDestroy也可以。你的例子显示了一种不良实践,一个内部类泄漏了它的外部类,这不仅适用于BroadcastReceiver,而且是程序员经常必须防范的事情。至于修改GUI,你可以存储一个状态,当Activity重新开始时使用该状态,而无需修改GUI。 - JohanShogun
显示剩余10条评论

135

我更倾向于全面回答。

  1. LocalbroadcastManager包含在Android 3.0及以上版本中,因此对于早期版本,您必须使用支持库v4。请参阅此处的说明。

  2. 创建一个广播接收器:

    private BroadcastReceiver onNotice= new BroadcastReceiver() {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // intent can contain anydata
            Log.d("sohail","onReceive called");
            tv.setText("Broadcast received !");
    
        }
    };
    
  3. 在activity的onResume中注册你的接收器,如下所示:

    protected void onResume() {
            super.onResume();
    
            IntentFilter iff= new IntentFilter(MyIntentService.ACTION);
            LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, iff);
        }
    
    //MyIntentService.ACTION is just a public static string defined in MyIntentService.
    
  4. 在onPause中取消注册接收器:

  5. protected void onPause() {
      super.onPause();
      LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
    }
    
  6. 现在无论是从应用程序的活动还是服务发送本地广播,都将调用onNotice的onReceive方法:)。

编辑:您可以在此处阅读完整的教程 LocalBroadcastManager:应用程序内消息传递


17
如果您的广播接收器在一个片段中,使用 LocalBroadcastManager.getInstance(getActivity()).registerReceiver(onNotice); 进行注册,并使用 LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onNotice); 取消注册。 - PeteH
3
你确定 LocalBroadcastManager 包含在 Android 3.0 及以上版本中吗?除了支持库之外我找不到它的任何相关信息。 - mente
5
奇怪的是,LBM 只包含在支持库中。 - Jeffrey Blattman
2
我相信你可能想将生命周期移至 onStop,因为在 Android API 24+ 中,“多窗口/分屏视图”(在 API 26+ 上默认启用)中,未与之交互的活动处于暂停状态。来源:https://developer.android.com/guide/topics/ui/multi-window.html#lifecycle - Martin Marconcini
2
@AJW 我不会这样做。我真的想不出有什么理由去这样做。这主要取决于你的使用情况。大多数情况下,onStop/Start 倾向于更好,因为对话框会触发 onPause,而可能不希望因为出现对话框而“取消订阅”某些内容(只是在稍后重新订阅)。或者在某些情况下,是的,所以...确保这就是你想要的 ;) - Martin Marconcini
显示剩余6条评论

47

接收端:

  • 首先注册本地广播接收器
  • 然后在onReceive中处理传入的意图数据。

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
      lbm.registerReceiver(receiver, new IntentFilter("filter_string"));
  }

  public BroadcastReceiver receiver = new BroadcastReceiver() {
      @Override
      public void onReceive(Context context, Intent intent) {
          if (intent != null) {
              String str = intent.getStringExtra("key");
              // get all your data from intent and do what you want 
          }
      }
  };

发送端:

   Intent intent = new Intent("filter_string");
   intent.putExtra("key", "My Data");
   // put your all data using put extra 

   LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

在我的情况下,只有当我在发送广播时设置意图中的操作时才起作用,否则onReceive()方法永远不会被调用... - Akash Bisariya

27
在Eclipse中,我必须通过右键单击我的项目并选择以下选项来添加兼容/支持库

Android工具 -> 添加支持库

一旦添加完成,我就可以在我的代码中使用LocalBroadcastManager类。


Android Compatibility Library


21

本地广播管理器已被弃用,请使用可观察模式的其他实现方式。

androidx.localbroadcastmanager 在版本 1.1.0 中已被弃用。

原因

LocalBroadcastManager 是一个应用程序范围的事件总线,会承认您的应用程序中的层次违规;任何组件都可以监听来自任何其他组件的事件。 它继承了系统 BroadcastManager 的不必要用例限制;即使对象仅存在于一个进程中并且永远不会离开该进程,开发人员也必须使用 Intent。由于同样的原因,它并没有跟随 BroadcastManager 的功能。

这些合起来会导致开发者体验混乱。

替代方案

您可以使用可观察模式的其他实现方式来替换 LocalBroadcastManager 的使用。根据您的用例,适当的选项可能是LiveData 或反应流。

LiveData 的优点

您可以使用单例模式扩展 LiveData 对象,以包装系统服务,以便在应用程序中共享。 LiveData 对象仅连接到系统服务一次,然后需要该资源的任何观察者都可以观察 LiveData 对象。

 public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(this, price -> {
            // Update the UI.
        });
    }
}

observe()方法将片段(即LifecycleOwner的实例)作为第一个参数传递。这样做表示此观察者绑定到与所有者关联的Lifecycle对象,即:

  • 如果Lifecycle对象未处于活动状态,则即使值更改,也不会调用观察者。

  • 在Lifecycle对象被销毁后,观察者会自动移除。

LiveData对象具有生命周期感知特性,这意味着可以在多个活动、片段和服务之间共享。


1
你说得没错,泄露上下文会影响整个应用程序,但我想知道如果我想从一个前台服务中进行通信,即使没有活动也在运行,但当活动出现时,它们需要进行通信,那么什么是合适的替代方案? - ateebahmed
3
创建一个单例类,其中包含一个 LiveData 对象,并从服务中发布数据。一旦 Activity 启动,Activity 可以轻松地观察该 LiveData,而不会造成任何影响。例如:MyServiceData.getInstance().getMyData().observe... - Darish
4
我会想念LocalBroadcastManager。如果它让Google的开发者感到困惑,也许他们需要停止过度设计? - Andrei Drynov
@Darish 这个单例类是否相当于将其存储在应用程序对象中?为什么这种全局状态在这些情况下不被认为是不良实践? - xuiqzy

15

如何将全局广播更改为本地广播

1)创建实例

LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);

2) 用于注册BroadcastReceiver的步骤

替换为

registerReceiver(new YourReceiver(),new IntentFilter("YourAction"));

使用

localBroadcastManager.registerReceiver(new YourReceiver(),new IntentFilter("YourAction"));

3) 发送广播消息

替换为

sendBroadcast(intent);

localBroadcastManager.sendBroadcast(intent);

4) 取消注册广播消息

替换为

unregisterReceiver(mybroadcast);

通过

localBroadcastManager.unregisterReceiver(mybroadcast);

我该如何注册多个IntentFilter? - Parikshit Chalke
@ParikshitChalke: link - XMAN

6
当你已经足够熟悉LocalBroadcastReceiver时,我建议你尝试一下Green Robot's EventBus - 你一定会意识到与LBR相比它的差异和有用性。代码更少,接收器线程可自定义(UI/Bg),检查接收器可用性,粘性事件,事件可用作数据传递等。

5

Kotlin版本使用LocalBroadcastManager

请查看以下代码进行注册发送接收广播消息。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // register broadcast manager
        val localBroadcastManager = LocalBroadcastManager.getInstance(this)
        localBroadcastManager.registerReceiver(receiver, IntentFilter("your_action"))
    }

    // broadcast receiver
    var receiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent != null) {
                val str = intent.getStringExtra("key")
                
            }
        }
    }

    /**
     * Send broadcast method
     */
    fun sendBroadcast() {
        val intent = Intent("your_action")
        intent.putExtra("key", "Your data")
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    override fun onDestroy() {
        // Unregister broadcast
        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
        super.onDestroy()
    }

}

2

0
enter code here if (createSuccses){
                        val userDataChange=Intent(BRODCAST_USER_DATA_CHANGE)
                        LocalBroadcastManager.getInstance(this).sendBroadcast(
                            userDataChange
                        )
                        enableSpinner(false)
                        finish()

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