How to use LocalBroadcastManager?
Asked Answered
F

13

480

How to use/locate LocalBroadcastManager as described in google docs and Service broadcast doc?

I tried to google it, but there is no code available to start with?

The documents say that I should use it if I want to do broadcast internally with in my app's process but I don't know where to look for this.

Any help/comment?

Update: I know how to use Broadcasts but don't know how to get LocalBroadcastManager available in my project.

Famous answered 10/1, 2012 at 10:57 Comment(4)
Waqas, have you registered the receiver in manifest. If yes, please let me know how?Shotton
I dont think you need to register receiver for such broadcasts in manifest, because if you do, then that receiver will also listen for global broadcasts.Famous
True. Then this means, I have to do it in code as given in the answer below; LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("custom-event-name"));Shotton
LocalBroadcastManager has been deprecated. I replaced mine with the EventBus library which is much nicer, imo.Anastassia
P
888

I'll answer this anyway. Just in case someone needs it.

ReceiverActivity.java

An activity that watches for notifications for the event named "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

The second activity that sends/broadcasts notifications.

@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);
}

With the code above, every time the button R.id.button_send is clicked, an Intent is broadcasted and is received by mMessageReceiver in ReceiverActivity.

The debug output should look like this:

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! 
Pelting answered 16/1, 2012 at 2:45 Comment(15)
thanks. got it working already. but the problem i faced was to get hold on LocalBroadcastManager class. Since its a support package class, so i wasn't able to use it in my ordinary package till i added Compatibility Library from Android Tools. Once its added, all went just fine. anyway, thanks for the answerFamous
please note that onDestroy() is not guaranteed to be called!!! You must use onPause() (because only onPause() is guaranteed) and onResume() (because it's the match for onPause())Incorporeity
@Incorporeity Isnt it possible to register on onCreate() and unregister on both onDestroy() and on onSaveInstanceState() ?Illsorted
onCreate() is not called e.g. when the user goes to the settings page and returns back. But if the user changes the screen orientation while on the settings page, onCreate is called. As to unregistering in onSaveInstanceState()... OMG... This is not the intended use, which means that the Google guys may change something and break your code.Incorporeity
Folks, note what the google docs now say about an Activity after onPause(): Killable = Pre-HONEYCOMB Starting with Honeycomb, an application is not in the killable state until its onStop() has returned.Incorporeity
onDestroy() is no problem. The case in which it is not called is when the app is killed, and it does not matter if you don't unregister in that case since not even the list of registered receivers survives that.Orleans
This is extremely useful! By the way, it's important to note that the line " LocalBroadcastManager.getInstance(this).sendBroadcast(intent);" is important, because the LBM's context is what receives broadcasts from the LBM. If you use other context, you will not receive message.Lethargy
of course using LocalBroadcastManager to communication between activities is a bad idea ... best pratices tells that recivers should be unregstered in onPause, because any interaction with UI after this point makes no sens ... also storing Activity references in some static class longer then it is visible is bad practice (weak references is ok but LocalBroadcastManager internally is not using em) ... Conclusion: You should never use LocalBroadcastManager to comunication between ActivitiesAdelaadelaida
of course it works because simple Log statement in receiver ... here we have something common(on button click in Sender we add some data to Adapter in Receiver = UI interaction) the code will end with nice java.lang.UnsupportedOperationException ... @Incorporeity got right ... we should unregister receiver in onPause ... but then we will not get intent :) ... only people who do not understand activities's lificycle upvote this question ...Adelaadelaida
@Adelaadelaida I hope you're aware that you can make the BroadcastReciever weakly referenced to the receiving activity and make it unregister itself if it's been orphaned. You don't need to unregister it in onPause, onDestroy is fine as long as you don't use your BroadcastReceiver to keep your activity in RAM. Your example shows a bad practice with an inner class leaking it's outer class, it's not unique to BroadcastReceiver and is something programmers always have to guard against. As for modifying the GUI, you can store a state for when the activity is resumed, you don't have to modify the GUI.Studbook
I also want to point out that I don't specifically advocate it's usage for communication between activities (although there are exceptions to every rule) but I do feel like I have to point out that you're example is only a problem because you rely on poor programming practices in it.Studbook
@Incorporeity If you use onPause() to unregister the receiver then the activity can't receive broadcasts in the background right? Doesn't that kind of defeat the purpose? Am I missing something here? Genuinely asking.Chomp
@Jackyesterday The shown code is a toy. It defines an activity that can receive broadcasts while it is on screen. The broadcast receiver in ReceiverActivity has access to the activity because it is an inner class. A real broadcast receiver uses its context parameter as the only available Context. A real broadcast receiver can either notify a service via a service intent, or start an activity via an activity intent. (continued below)Incorporeity
@Jackyesterday (continued) (I mean that the class specified in the intent may specify a service or an activity, and these two cases are very different because an application that uses services is very much different from an application that uses only activities.) So in real code there would be cumbersome packing/unpacking data to/from an Intent. (Just think: in 1960-es our ancestors believed that a name and a list of parameters is just enough.)Incorporeity
If you need to change views or replace fragments, you need to register it in onResume() and unregister in onPause(), otherwise it can throw an “IllegalStateException: Can not perform this action after onSaveInstanceState”. This will also cut down on unnecessary system overhead.Courtnay
P
135

I'd rather like to answer comprehensively.

  1. LocalbroadcastManager included in android 3.0 and above so you have to use support library v4 for early releases. see instructions here

  2. Create a broadcast receiver:

    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. Register your receiver in onResume of activity like:

    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. unRegister receiver in onPause:

    protected void onPause() {
      super.onPause();
      LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
    }
    
  5. Now whenever a localbroadcast is sent from applications' activity or service, onReceive of onNotice will be called :).

Edit: You can read complete tutorial here LocalBroadcastManager: Intra application message passing

Pubilis answered 26/4, 2012 at 5:18 Comment(11)
+1. if your Broadcast Receiver is in a fragment, register it using LocalBroadcastManager.getInstance(getActivity()).registerReceiver(onNotice); and unregister it using LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onNotice);Pulcheria
Are you sure that LocalBroadcastManager is included in Android 3.0 and up? Can not find it anywhere except support libElanorelapid
strangely, LBM is only included in the support library.Jesuit
So it is not necessary to include android-support-v4.jar to target 11 and up in order to use LocalBroadcastManager?Liebowitz
@Pulcheria you missed IntentFilter in registereRecevier method.Greensand
super.onPause() should be last statement when overwriting onPause method. Unregister before super.onPause to avoid unpredictable bugGodfree
I believe you may want to move your lifecycle to onStop because in Android API 24+ with “Multi-Window/Split-View” (enabled by default on API 26+ affaicr), the activity not being interacted with is in the paused state. Source: developer.android.com/guide/topics/ui/…Percy
@Martin Marconcini does your recommendation to use onStop() to unregister the LBM imply that onStart() should be used to register the LBM?Sasaki
@Sasaki preferably, yes. The more you mirror these calls, the easier it is to understand their lifecycle.Percy
@Martin Marconcini Also, should onStop() and onStart() only be used for API 24+ and use onPause() and onResume() be used for API < 24?Sasaki
@Sasaki I wouldn’t. There’s really no reason to do that (that I can think of). It really depends on your use case. For the most part, onStop/Start tends to be better given that a Dialog will trigger onPause and it may not be desired to “unsubscribe” to things (only to resubscribe moments later) because a Dialog appeared. Or in some cases yes, so… ensure that’s what you want ;)Percy
H
47

On Receiving end:

  • First register LocalBroadcast Receiver
  • Then handle incoming intent data in 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 
              }
          }
      };
    

On Sending End:

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

   LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Holytide answered 18/11, 2016 at 7:48 Comment(1)
In my case only when I set action in intent when sending broadcast works otherwise onReceive() method never called...Marthena
F
27

In Eclipse, eventually I had to add Compatibility/Support Library by right-clicking on my project and selecting:

Android Tools -> Add Support Library

Once it was added, then I was able to use LocalBroadcastManager class in my code.


Android Compatibility Library

Famous answered 17/2, 2012 at 11:39 Comment(0)
P
21

localbroadcastmanager is deprecated, use implementations of the observable pattern instead.

androidx.localbroadcastmanager is being deprecated in version 1.1.0

Reason

LocalBroadcastManager is an application-wide event bus and embraces layer violations in your app; any component may listen to events from any other component. It inherits unnecessary use-case limitations of system BroadcastManager; developers have to use Intent even though objects live in only one process and never leave it. For this same reason, it doesn’t follow feature-wise BroadcastManager .

These add up to a confusing developer experience.

Replacement

You can replace usage of LocalBroadcastManager with other implementations of the observable pattern. Depending on your use case, suitable options may be LiveData or reactive streams.

Advantage of LiveData

You can extend a LiveData object using the singleton pattern to wrap system services so that they can be shared in your app. The LiveData object connects to the system service once, and then any observer that needs the resource can just watch the LiveData object.

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

The observe() method passes the fragment, which is an instance of LifecycleOwner, as the first argument. Doing so denotes that this observer is bound to the Lifecycle object associated with the owner, meaning:

  • If the Lifecycle object is not in an active state, then the observer isn't called even if the value changes.

  • After the Lifecycle object is destroyed, the observer is automatically removed

The fact that LiveData objects are lifecycle-aware means that you can share them between multiple activities, fragments, and services.

Procuration answered 19/1, 2019 at 6:8 Comment(4)
you are right about leaking contexts to whole world, but I would like to know what would be a suitable replacement when I want to communicate from a foreground service that is running even without an activity, but when activity comes in, they need to communicate?Garwin
Create a singleton class with a LiveData object and post your data from the service. Once the activity launches, activity can easily observe the LiveData without any harm. eg: MyServiceData.getInstance().getMyData().observe ...Procuration
I will miss LocalBroadcastManager. If it was confusing to developers at Google, perhaps they need to stop over-engineering things?Valediction
@Procuration Would this singleton class be equivalent to storing it in the Application object? Why is this kind of global state in these cases not considered bad practice?Tug
S
15

How to change your global broadcast to LocalBroadcast

1) Create Instance

LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);

2) For registering BroadcastReceiver

Replace

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

With

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

3) For sending broadcast message

Replace

sendBroadcast(intent);

With

localBroadcastManager.sendBroadcast(intent);

4) For unregistering broadcast message

Replace

unregisterReceiver(mybroadcast);

With

localBroadcastManager.unregisterReceiver(mybroadcast);
Stowaway answered 2/3, 2018 at 6:0 Comment(2)
How can I register multiple IntentFilter??Unrepair
@ParikshitChalke: linkGrenier
S
6

When you'll play enough with LocalBroadcastReceiver I'll suggest you to give Green Robot's EventBus a try - you will definitely realize the difference and usefulness of it compared to LBR. Less code, customizable about receiver's thread (UI/Bg), checking receivers availability, sticky events, events could be used as data delivery etc.

Snowber answered 8/8, 2016 at 7:16 Comment(0)
T
5

Kotlin version of using LocalBroadcastManager:

Please check the below code for registering, sending and receiving the broadcast message.

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

}
Tideland answered 21/6, 2020 at 16:26 Comment(0)
A
2

An example of an Activity and a Service implementing a LocalBroadcastManager can be found in the developer docs. I personally found it very useful.

EDIT: The link has since then been removed from the site, but the data is the following: https://github.com/carrot-garden/android_maven-android-plugin-samples/blob/master/support4demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java

Adiaphorous answered 14/6, 2012 at 14:15 Comment(0)
R
0
enter code here if (createSuccses){
                        val userDataChange=Intent(BRODCAST_USER_DATA_CHANGE)
                        LocalBroadcastManager.getInstance(this).sendBroadcast(
                            userDataChange
                        )
                        enableSpinner(false)
                        finish()
Rackety answered 15/3, 2020 at 16:31 Comment(0)
R
0

By declaring one in your AndroidManifest.xml file with the tag (also called static)

<receiver android:name=".YourBrodcastReceiverClass"  android:exported="true">
<intent-filter>
    <!-- The actions you wish to listen to, below is an example -->
    <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>

You will notice that the broadcast receiver declared above has a property of exported=”true”. This attribute tells the receiver that it can receive broadcasts from outside the scope of the application.
2. Or dynamically by registering an instance with registerReceiver (what is known as context registered)

public abstract Intent registerReceiver (BroadcastReceiver receiver, 
            IntentFilter filter);

public void onReceive(Context context, Intent intent) {
//Implement your logic here
}

There are three ways to send broadcasts:
The sendOrderedBroadcast method, makes sure to send broadcasts to only one receiver at a time. Each broadcast can in turn, pass along data to the one following it, or to stop the propagation of the broadcast to the receivers that follow.
The sendBroadcast is similar to the method mentioned above, with one difference. All broadcast receivers receive the message and do not depend on one another.
The LocalBroadcastManager.sendBroadcast method only sends broadcasts to receivers defined inside your application and does not exceed the scope of your application.

Rackety answered 15/3, 2020 at 17:16 Comment(0)
D
0

I am an iOS dev, so I made a solution similar to NotificationCenter:

object NotificationCenter {
    var observers: MutableMap<String, MutableList<NotificationObserver>> = mutableMapOf()

    fun addObserver(observer: NotificationObserver, notificationName: NotificationName) {
        var os = observers[notificationName.value]
        if (os == null) {
            os = mutableListOf<NotificationObserver>()
            observers[notificationName.value] = os
        }
        os.add(observer)
    }

    fun removeObserver(observer: NotificationObserver, notificationName: NotificationName) {
        val os = observers[notificationName.value]
        if (os != null) {
            os.remove(observer)
        }
    }

    fun removeObserver(observer:NotificationObserver) {
        observers.forEach { name, mutableList ->
            if (mutableList.contains(observer)) {
                mutableList.remove(observer)
            }
        }
    }

    fun postNotification(notificationName: NotificationName, obj: Any?) {
        val os = observers[notificationName.value]
        if (os != null) {
            os.forEach {observer ->
                observer.onNotification(notificationName,obj)
            }
        }
    }
}

interface NotificationObserver {
    fun onNotification(name: NotificationName,obj:Any?)
}

enum class NotificationName(val value: String) {
    onPlayerStatReceived("on player stat received"),
    ...
}

Some class that want to observe notification must conform to observer protocol:

class MainActivity : AppCompatActivity(), NotificationObserver {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        NotificationCenter.addObserver(this,NotificationName.onPlayerStatReceived)
    }
    override fun onDestroy() {
        ...
        super.onDestroy()
        NotificationCenter.removeObserver(this)
    }

    ...
    override fun onNotification(name: NotificationName, obj: Any?) {
        when (name) {
            NotificationName.onPlayerStatReceived -> {
                Log.d(tag, "onPlayerStatReceived")
            }
            else -> Log.e(tag, "Notification not handled")
        }
    }

Finally, post some notification to observers:

NotificationCenter.postNotification(NotificationName.onPlayerStatReceived,null)
Delozier answered 2/10, 2020 at 8:50 Comment(0)
D
-4

we can also use interface for same as broadcastManger here i am sharing the testd code for broadcastManager but by interface.

first make an interface like:

public interface MyInterface {
     void GetName(String name);
}

2-this is the first class that need implementation

public class First implements MyInterface{

    MyInterface interfc;    
    public static void main(String[] args) {
      First f=new First();      
      Second s=new Second();
      f.initIterface(s);
      f.GetName("Paddy");
  }
  private void initIterface(MyInterface interfc){
    this.interfc=interfc;
  }
  public void GetName(String name) {
    System.out.println("first "+name);
    interfc.GetName(name);  
  }
}

3-here is the the second class that implement the same interface whose method call automatically

public class Second implements MyInterface{
   public void GetName(String name) {
     System.out.println("Second"+name);
   }
}

so by this approach we can use the interface functioning same as broadcastManager.

Dehiscent answered 22/6, 2016 at 17:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.