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.