Android Mosby MVI绑定到演示者中的服务

时间:2017-03-27 09:34:44

标签: android android-service android-service-binding mosby

我正在使用Mosby创建一个小应用程序。

该应用有一项我想要绑定的服务。我想在演示者中这样做的正确位置。但我无法弄明白该怎么做。

我想要存档的是绑定服务时我想在其上调用一个方法并将该值推送到视图,以便现在的状态是正确的。

当服务在事件总线上发送更新时,我想将其推送到视图中。

我在后面的部分找到了一些示例,但没有关于如何在演示者中绑定/取消绑定服务的内容。

我的努力就是在活动中创建这样的东西:

@NonNull
@Override
public MyPresenter createPresenter() {
    return new MyPresenter(new MyService.ServiceHandler() {
            @Override
            public void start(ServiceConnection connection) {
                Intent intent = new Intent(MyActivity.this, MyService.class);
                startService(intent);
                bindService(intent, connection, Context.BIND_AUTO_CREATE);
            }

            @Override
            public void stop(ServiceConnection connection) {
                unbindService(connection);
            }
        });

然后在演示者中做这样的事情:

private ServiceConnection connection;
private boolean bound;
private MyService service;

public MyPresenter(MyService.ServiceHandler serviceHandler) {
    super(new MyViewState.NotInitialiezedYet());

    this.serviceHandler = serviceHandler;

    connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
           MyService.LocalBinder binder = (MyService.LocalBinder) service;
            service = binder.getService();
            bool isInitialized = service.isInitialized();
            // how do i push isInitialized to view? 

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };
}

@Override
public void attachView(@NonNull SplashView view) {
    super.attachView(view);
    serviceHandler.start(connection);
    bound = true;
}

@Override
public void detachView(boolean retainInstance) {
    super.detachView(retainInstance);
    if(bound) {
        serviceHandler.stop(connection);
        bound = false;
    }
}

@Override
protected void bindIntents() {
    //Not sure what this would look like?
}

public void onEventInitialized(InitializedEvent event) {
    //how do I push this to the view?
 }   

我在正确的道路上吗?这样做的正确方法是什么?我如何将服务中的值发送到onServiceConnected中的视图,以及何时在onEventInitialized中获取事件总线上的事件?

1 个答案:

答案 0 :(得分:4)

在深入研究可能的实施之前需要注意的一些事项:

  1. 在Mosby中,Presenters在默认情况下仍然存在屏幕方向,只是视图已连接/分离。如果在ServiceHandler中创建Activity,则会导致内存泄漏,因为ServiceHandler是在Activity中实例化的annonaymous类,因此具有对外部Activity实例的引用。为避免这种情况,您可以使用Application类作为上下文来调用bindService()unbindService()
  2. 服务是业务逻辑,因此您最好将绑定服务的逻辑放入View层(Activity),而不是它自己的"业务逻辑"组件,即让我们调用此组件MyServiceInteractor
  3. 当您在业务逻辑中移动该部分时,您可能想知道何时解除绑定/停止服务。在您的代码中,您已在Presenter detachView()中完成了该操作。虽然这有效,但Presenter现在对业务逻辑内部及其工作方式有一些明确的了解。更符合Rx的解决方案是将服务连接的生命周期与“生命周期”联系起来。一个Rx Observable。这意味着,一旦取消订阅/处置可观察量,就应该关闭服务连接。这也与1完美匹配。" Presenter在屏幕方向改变后生存下来" (并在屏幕方向更改期间保持可观察的订阅活动)。
  4. 任何回调/听众都可以很容易地被"包裹"使用Observable.create()
  5. 进入Rx Observable
  6. 我个人认为服务(特别是有限服务)很麻烦,并且在代码中引入了更高的复杂性。如果没有服务,你可能(或可能不是)能够实现同样的目标。但这实际上取决于您的具体应用/用例。
  7. 话虽如此,让我们看看可能的解决方案是什么样的(伪相似的代码,可能无法编译):

    public class MyServiceInteractor {
    
      private Context context;
    
      public MyServiceInteractor(Context context) {
        this.context = context.getApplicationContext();
      }
    
      public Observable<InitializedEvent> getObservable() {
        return Observable.create(emitter -> {
          if (!emitter.isDisposed()) {
    
            MyService.ServiceHandler handler = new MyService.ServiceHandler() {
    
              @Override public void start(ServiceConnection connection) {
                Intent intent = new Intent(context, MyService.class);
                context.startService(intent);
                context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
              }
    
              @Override public void stop(ServiceConnection connection) {
                context.unbindService(connection);
              }
            };
    
            emitter.onNext(handler);
            emitter.onComplete();
          }
        }).flatMap(handler ->
            Observable.create( emitter -> {
              ServiceConnection connection = new ServiceConnection() {
                @Override public void onServiceConnected(ComponentName name, IBinder service) {
                  MyService.LocalBinder binder = (MyService.LocalBinder) service;
                  MyService service = binder.getService();
                  boolean isInitialized = service.isInitialized();
                  if (!emitter.isDisposed())
                     emitter.onNext(new InitializedEvent(isInitialized));
                }
    
                @Override public void onServiceDisconnected(ComponentName name) {
                  // you may want to emit an event too
                }
              };
    
            })
            .doOnDispose({handler.stop()})
        );
      }
    }
    

    所以基本上MyServiceInteractor.getObservable()创建了一个到Rx Observable世界的桥梁,并在observable得到取消时停止服务连接。请注意,此代码段可能无法编译。它仅用于说明可能的解决方案/工作流程的外观。

    然后你的Presenter看起来像这样:

    public class MyPresenter extends MviBasePresenter<MyView, InitializedEvent> {
      private MyServiceInteractor interactor;
    
      public MyPresenter(MyServiceInteractor interactor){
         this.interactor = interactor;
      }
    
      @Override
      void bindIntents(){
        Observable<InitializedEvent> o = intent(MyView::startLoadingIntent) // i.e triggered once in Activity.onStart()
            .flatMap( ignored -> interactor.getObservable() );
    
        subscribeViewState(o, MyView::render);
      }
    }
    

    所以这里的主要问题/问题不是MVI或MVP或MVVM特定的,它主要是我们如何&#34;包装&#34; android服务回调到RxJava observable。 一旦我们有了这个,其余的应该很容易。

    唯一与MVI相关的是连接点:视图实际上必须触发启动服务连接的意图。这是通过bindIntents()

    myView.startLoadingIntent()中完成的

    我希望有所帮助。