首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android Mosby MVI绑定到演示器中的服务

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

Stack Overflow用户
提问于 2017-03-27 09:34:43
回答 1查看 679关注 0票数 2

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

该应用程序有一个服务,我想绑定到。我想正确的地方是在推荐人那里。但我真的想不出怎么做。

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

当服务在事件总线上发送更新时,我也希望将它推送到视图中。

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

我的目的是在活动中创建这样的东西:

代码语言:javascript
复制
@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);
            }
        });

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

代码语言:javascript
复制
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中的事件总线上获得事件时?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-27 13:10:37

在我们深入研究一个可能的实现之前,需要注意几点:

  1. 在Mosby中,显示者在每个默认的屏幕方向下生存下来,只有视图被附加/分离。如果在ServiceHandler中创建Activity,则会出现内存泄漏,因为ServiceHandler是在活动中实例化的annonaymous类,因此具有对外部活动实例的引用。为了避免这种情况,可以使用Application类作为上下文来调用bindService()unbindService()
  2. 服务是业务逻辑,所以最好不要将绑定服务的逻辑放在视图层(活动)中,而应该放在它自己的“业务逻辑”组件中,即让我们调用这个组件MyServiceInteractor
  3. 当您在业务逻辑中移动该部分时,您可能想知道何时解除绑定/停止服务。在您的代码中,您已经在演示器detachView()中这样做了。虽然这是可行的,但演示者现在对业务逻辑内部及其工作方式有了一些明确的了解。更相似的解决方案是将服务连接的生命周期与可观察的Rx的“生命周期”联系起来。这意味着,一旦可观察到的服务连接被取消订阅/处理,服务连接就应该关闭。这也与1完全匹配。“演示者在屏幕方向变化中生存下来”(并在屏幕方向变化期间保持可观察的订阅活动)。
  4. 任何回调/侦听器都可以很容易地“包装”到使用Observable.create()可以观察到的Rx中。
  5. 就我个人而言,我发现服务(尤其是有限制的服务)处理起来很麻烦,并在代码中引入了更高的复杂性。您可能(或不可能)能够在没有服务的情况下实现相同的目标。但它确实取决于您的具体应用程序/用例。

尽管如此,让我们看看一个可能的解决方案是怎样的(伪代码,可能不会编译):

代码语言:javascript
复制
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可观察世界的桥梁,并在可观察的get不可分的情况下停止了服务连接。请注意,此代码段可能无法编译。这只是为了说明一个可能的解决方案/工作流是什么样子的。

那么您的Presenter可能如下所示:

代码语言:javascript
复制
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特有的,主要是我们如何将android回调“包装”到一个可观察到的RxJava中。一旦我们有了这个,剩下的就很容易了。

唯一与MVI相关的事情是连接点:视图实际上必须触发启动服务连接的意图。这是在bindIntents()中通过myView.startLoadingIntent()完成的

我希望这能帮上忙。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43042785

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档