Android 服务片段通信

Android 服务片段通信,android,android-intent,android-service,rx-java,greenrobot-eventbus,Android,Android Intent,Android Service,Rx Java,Greenrobot Eventbus,活动包含一个片段,该片段又包含一个子片段,该子片段请求一个服务。该应用程序尝试实现rest体系结构 当服务完成工作时,它必须传播操作结果。我尝试使用一个pendingent,但它似乎只被活动捕获,而我需要子片段得到通知。你有什么建议吗?粘合剂绿色巴士?RxJava(我在项目中已经有了) 谢谢。试试这个方法,希望对你有帮助 例如: 您的服务 public class MyService extends Service{ public static MyServiceListener ge

活动
包含一个
片段
,该片段又包含一个子
片段
,该子片段请求一个
服务
。该应用程序尝试实现rest体系结构

服务
完成工作时,它必须传播操作结果。我尝试使用一个
pendingent
,但它似乎只被活动捕获,而我需要子片段得到通知。你有什么建议吗?粘合剂绿色巴士?RxJava(我在项目中已经有了)


谢谢。

试试这个方法,希望对你有帮助

例如:

您的服务

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);
        }
    }
}
你的片段

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

我建议使用事件总线来完成这类事情。它将允许您向系统中的组件发送消息,而无需创建特殊的处理程序


Otto是一个流行的开源库,还有其他一些

我目前正在开发一种完全基于RxJava的总线。因为您的项目中已经有了RxJava,所以您可以使用它来实现这一点。您应该使用BehaviorSubject和Observable.switchOnNext()

例如:

private BehaviorSubject<Observable<Whatever>> subject = BehaviorSubject.create();

public void post(){
    subject.onNext(...);
}

public Observable<Whatever> subscribe(){
    return Observable.switchOnNext(subject);
}
private BehaviorSubject subject=BehaviorSubject.create();
公共空缺职位(){
主题.onNext(…);
}
公共可观测订阅(){
返回可观察。开关下一个(主题);
}
您应该将其作为Singleton的一部分,以便使用相同的BehaviorSubject。您所要做的就是从一个片段发布()并在另一个片段或任何其他感兴趣的片段或活动中订阅()。您可以拥有任意数量的订阅,另外,如果您正确地实现了它,那么最后发出的可观察对象将在方向更改后仍然存在


关于BehaviorSubject的更多信息可以在这里找到:

我目前正在rxjava和enum类中使用这个发布/订阅模式

public enum Events {

  public static PublishSubject <Object> myEvent = PublishSubject.create ();
}
//您希望接收事件的位置

Events.myEvent.subscribe (...); 
RxJava 一种简单的方法是使用单例包装同步的“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());
}
并在片段中或任何需要的时候响应事件

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();
    }
}
公共类MyFragment扩展了片段{
// [...]
认购主题1;
@凌驾
恢复时公开作废(){
super.onResume();
订阅\u topic1=EventBusRx.getInstance().topic2
.subscribeOn(AndroidSchedulers.mainThread())//或在其他调度程序上
.订阅(新操作1(){
@凌驾
公共无效调用(整数){
//更新用户界面
}
});
}
@凌驾
公共无效暂停(){
//避免内存泄漏非常重要
订阅主题1.取消订阅();
super.onPause();
}
}
不要忘记取消订阅

这个想法类似于Roger'one使用单例,但强制执行ThreadSafety包装主题

不需要可观察。switchOnNext(主题)

事件总线库 greenRobot Eventbus和Otto很不错,功能相同,但缺点是它们使连接更加模糊(尤其是Eventbus)。如果你已经使用rx,我认为最好还是继续使用它

这是一篇关于这个话题的独创性文章

本地广播
实现这一点的经典方法是使用,但在我的AOP中,它们是一个难题

我会使用基于rx的事件总线。 将其设置为sigletone并订阅特定的类类型

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);
    }
}
发送消息:

Message m = new Message();
m.result = "Hello world";
RxBus.getInstance().send(m);
订阅特定的类类型:

RxBus.getInstance().observe(Message.class).subscribe(msg -> Log.e(TAG, "Message was caught : " + msg));

为什么不使用一个接口呢?如果你真的喜欢使用意图,那么在片段中注册一个BroadcastReceiver应该是你的解决方案,也许看看,这似乎是相关的:这种方法是如此的内存泄漏。它与runOnUiThread无关。您对本质上不稳定的资源有一个强大的静态引用。这样可以防止GC
class Message { public String result};
Message m = new Message();
m.result = "Hello world";
RxBus.getInstance().send(m);
RxBus.getInstance().observe(Message.class).subscribe(msg -> Log.e(TAG, "Message was caught : " + msg));