As per the official documentation of LocalBroadcastManager:
This class is deprecated. LocalBroadcastManager is an application-wide
event bus and embraces layer violations in your app: any component may
listen events from any other. You can replace usage of
LocalBroadcastManager with other implementation of observable pattern,
depending on your usecase suitable options may be
androidx.lifecycle.LiveData or reactive streams.
So you can replace it with other observable pattern like LiveData
or reactive streams. Because LiveData
is most popular nowadays and it is lifecycle-aware which ensures that it updates app component observers like activities, fragments, or services which have an active lifecycle state only below i will describe the steps to replace the LocalBroadcastManager
using LiveData
.
1.)Declare a NotificationLiveData
class which extends from LiveData<T>
where T is a String in the below example:
public class NotificationLiveData extends LiveData<String> {
public void setNotification(String message){
postValue(message);
}
}
2.)Declare a NotificationManager
class which is responsible to update the message like below:
public class NotificationManager {
private static final NotificationLiveData notificationLiveData = new NotificationLiveData();
public static void updateNotificationMessage(String message){
notificationLiveData.setNotification(message);
}
public static NotificationLiveData getNotificationLiveData() {
return notificationLiveData;
}
}
3.)In every Activity
you want to listen for updates you can observe the change like below:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NotificationManager.getNotificationLiveData().observe(this, notificationObserver);
}
private final Observer<String> notificationObserver = new Observer<String>() {
@Override
public void onChanged(String s) {
//do anything after a change happened
}
};
4.)In every Fragment
you want to listen for updates you can observe the change like below:
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
NotificationManager.getNotificationLiveData().observe(getViewLifecycleOwner(), notificationObserver);
}
private final Observer<String> notificationObserver = new Observer<String>() {
@Override
public void onChanged(String s) {
//do anything after a change happened
}
};
5.)From your Service
you can send a message like below:
NotificationManager.updateNotificationMessage("My message");
6.)Finally don't forget to remove the observer from any Activity
or Fragment
in onDestroy()
method like below:
@Override
protected void onDestroy() {
super.onDestroy();
NotificationManager.getNotificationLiveData().removeObserver(notificationObserver);
}
The above will listen the change only when the Activity/Fragment
has an active lifecycle state. In case you want to listen always the change independent of the lifecycle state you can use observeForever
instead of observe
like below:
NotificationManager.getNotificationLiveData().observeForever(notificationObserver);
Update:
As per your new requirement having multiple of background Threads which are sending simultaneously a number of Tokens you cannot use anymore the postValue
method as it does not guarantee that the specific Token will be received from the observer if the postValue
is called a lot of times simultaneously so in that case only the latest token will be received to the observer. You can test this if you call the postValue()
and immediately call the getValue()
method where you may not receive the value you have just set. However this can be solved only by using the setValue
method which is executed from the Main Thread only. When the Main Thread sets the value, then you will get immediately the value in the observer but be careful the observe
listens the change only if the Activity/Fragment
has an active lifecycle state. If you want to listen always the change independent of the lifecycle you must use the observeForever
instead.
So you need to change the NotificationLiveData
class to use the setValue
in the Main Thread like below:
public class NotificationLiveData extends MutableLiveData<String> {
public void setNotification(String message){
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
setValue(message);
}
});
}
}
But in the Multithreading environment it is better to use RxJava
which uses reactive streams for sending bunch of data simultaneously. RxJava
has a better level of abstraction around threading which simplifies the implementation of complex concurrent behavior so it suits better in this case. Below i will describe how you can achieve this using RxJava
instead of LiveData
.
RxJava - Approach
1.)First declare in your app dependencies the below Reactivex
implementations:
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
Here is the official documentation of ReactiveX/RxAndroid for more details.
2.)Declare the new NotificationManager
class to be like the below:
public class NotificationManager {
private static final Subject<String> notificationSubject = PublishSubject.create();
public static void updateNotificationMessage(String message){
notificationSubject.onNext(message);
}
public static Subject<String> getNotificationSubject() {
return notificationSubject;
}
}
The PublishSubject
represents an Observer
and an Observable
at the same time, allowing multicasting events from a single source to multiple child Observers. It emits to an observer all the subsequent items of the source Observable at the time of the subscription.
3.)You can subscribe to any Activity
like the below sample:
Disposable disposable = NotificationManager.getNotificationSubject()
.doOnNext(s -> { Log.d("OnNext=", s);})
.doOnComplete(() -> { })
.doOnError(throwable -> { })
.subscribe();
The doOnNext
is called every time you do a call to the notificationSubject.onNext(token)
.
4.)In your Service
in each of your Threads you can emit simultaneously the new tokens like the below sample:
Thread thread1 = new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
NotificationManager.updateNotificationMessage("Thread1:" + i);
}
}
};
thread1.start();
Thread thread2 = new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
NotificationManager.updateNotificationMessage("Thread2:" + i);
}
}
};
thread2.start();
5.) Finally in onDestroy()
method of your Activity
you have to dispose the PublishSubject
like below:
@Override
protected void onDestroy() {
super.onDestroy();
disposable.dispose();
}
And the results of the above multithreading example will be something like the below:
D/OnNext=: Thread2:0
D/OnNext=: Thread2:1
D/OnNext=: Thread2:2
D/OnNext=: Thread2:3
D/OnNext=: Thread2:4
D/OnNext=: Thread2:5
D/OnNext=: Thread1:0
D/OnNext=: Thread2:6
D/OnNext=: Thread2:7
D/OnNext=: Thread1:1
D/OnNext=: Thread2:8
D/OnNext=: Thread1:2
D/OnNext=: Thread2:9
D/OnNext=: Thread1:3
D/OnNext=: Thread1:4
D/OnNext=: Thread1:5
D/OnNext=: Thread1:6
D/OnNext=: Thread1:7
D/OnNext=: Thread1:8
D/OnNext=: Thread1:9
Also if you know when the transmission of data is finished you can simply use the notificationSubject.onComplete()
method and the .doOnComplete(() -> { })
will be called in the Activity
and automatically disposes the PublishSubject
Observable
. A similar call can be used when something goes wrong using the notificationSubject.onError(new Throwable())
which triggers the Activity
.doOnError(throwable -> { })
callback.