Reputation: 3412
An Activity
contains a Fragment
which in turn contains a child Fragment
, which requests a Service
. The app tries to implement dobjanschi rest architecture.
When the Service
is done working it has to propagate operation result. I tried using a PendingIntent
but it seems to only be caught by the activity, while I need the child fragment to get notified. Could you suggest anything? Binder? greenRobot Eventbus? RxJava (which I already have in the project)?
Thanks.
Upvotes: 2
Views: 4319
Reputation: 1771
I would use event bus, which is based on rx. Make this as a sigletone and subscribe on particular class type.
public class RxBus {
private static final RxBus sBus = new RxBus();
private final Subject<Object, Object> mBus = new SerializedSubject<>(PublishSubject.create());
private RxBus() {
}
public static RxBus getInstance() {
return sBus;
}
public void send(Object o) {
mBus.onNext(o);
}
public Observable<Object> observe() {
return mBus;
}
@SuppressWarnings("unchecked")
public <T> Observable<T> observe(Class<T> c) {
return mBus.filter(o -> c.isAssignableFrom(o.getClass())).map(o -> (T) o);
}
}
usage:
class Message { public String result};
send a message:
Message m = new Message();
m.result = "Hello world";
RxBus.getInstance().send(m);
subscribe on a particular class type:
RxBus.getInstance().observe(Message.class).subscribe(msg -> Log.e(TAG, "Message was caught : " + msg));
Upvotes: 0
Reputation: 349
A simple way con be to use a Singleton to wrap a synchronized ´PublishSubject´
* Singleton
*
* to send an event use EventBusRx.getInstance().topic1.onNext("completed");
*/
public class EventBusRx {
private static EventBusRx ourInstance = new EventBusRx();
public static EventBusRx getInstance() {
return ourInstance;
}
private EventBusRx() {}
/**
* Use of multiple topics can be usefull
* SerializedSubject avoid concurrency issues
*/
public final Subject<String, String> topic1 = new SerializedSubject<>(PublishSubject.create());
public final Subject<Integer, Integer> topic2 = new SerializedSubject<>(PublishSubject.create());
}
And You can send events from service
EventBusRx.getInstance().topic1.onNext("completed");
and respond to event in fragments or whenever you want
public class MyFragment extends Fragment {
// [...]
Subscription subscription_topic1;
@Override
public void onResume() {
super.onResume();
subscription_topic1 = EventBusRx.getInstance().topic2
.subscribeOn(AndroidSchedulers.mainThread()) // or on other sheduler
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
// update ui
}
});
}
@Override
public void onPause() {
// important to avoid memory leaks
subscription_topic1.unsubscribe();
super.onPause();
}
}
do not forget to unsubcribe the Subscription
The idea is similar to Roger'one use a singleton but enforce ThreadSafety wrapping PublishSubject.
there is no need for Observable.switchOnNext(subject)
greenRobot Eventbus and Otto are nice and has the same functionality, but the disadvantage is that they make the connection more smoky (expecialy EventBus) . If you already use rx i think is better to stay with it
Here is an insipring article about the topic Implementing an Event Bus With RxJava
The classic way to do this is to use LocalBroadcastManager but in my aopinion they are a pain
Upvotes: 6
Reputation: 6594
I'm currently using this Pub/Sub pattern with rxjava and enum class.
public enum Events {
public static PublishSubject <Object> myEvent = PublishSubject.create ();
}
//where you want to publish something
Events.myEvent.onNext(myObject);
//where you want to receive an event
Events.myEvent.subscribe (...);
Upvotes: 0
Reputation: 624
I'm currently developing a Bus based solely on RxJava. Since you already have RxJava on your project, you can use it for this. You should use a BehaviorSubject and Observable.switchOnNext().
For example:
private BehaviorSubject<Observable<Whatever>> subject = BehaviorSubject.create();
public void post(){
subject.onNext(...);
}
public Observable<Whatever> subscribe(){
return Observable.switchOnNext(subject);
}
You should have this as part of a Singleton so the same BehaviorSubject is used. All you have to do is post() from one fragment and subscribe() on the other one or in any other interested fragment or activity. You can have as many subscriptions as you want, plus if you implement it correctly then the last emitted Observable will survive orientation changes.
More info on BehaviorSubject can be found here: https://github.com/ReactiveX/RxJava/wiki/Subject
Upvotes: 0
Reputation: 28484
Try this way hope it help you.
For Example:
YourService
public class MyService extends Service{
public static MyServiceListener getMyServiceListener() {
return MyService.myServiceListener;
}
public static void setMyServiceListener(MyServiceListener myServiceListener) {
MyService.myServiceListener = myServiceListener;
}
private static MyServiceListener myServiceListener;
public interface MyServiceListener{
void onResult(String response);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
executeYourTask();
}
private void executeYourTask(){
String result = "SomeResultMaybeFromServer";
if(getMyServiceListener()!=null){
getMyServiceListener().onResult(result);
}
}
}
YourFragment
public class MyFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = null; // some view
// Start service
MyService.setMyServiceListener(new MyService.MyServiceListener() {
@Override
public void onResult(String response) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
// To handle memory/window leaks
}
});
}
});
return v;
}
}
Upvotes: 0
Reputation: 18725
I would suggest using an Event Bus for this sort of thing. It will allow you to send messages to components within your system, without requiring creating special handlers.
Otto is a popular open source library for this, and there are others. http://square.github.io/otto/
Upvotes: 0