gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 10:19:01 25 4
gpt4 key购买 nike

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

该应用程序有一个我想要绑定(bind)的服务。我想正确的位置是在演示者中。但我实在不知道该怎么做。

我想要存档的是,当服务绑定(bind)时,我想调用它的方法并将该值推送到 View ,以便现在的状态是正确的。

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

我在后面的部分找到了一些示例,但没有介绍如何在演示者中绑定(bind)/取消绑定(bind)服务。

我的尝试是在 Activity 中创建类似的东西:

@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?
}

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

最佳答案

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

  1. 在 Mosby 中,演示者默认保持屏幕方向,仅附加/分离 View 。如果您在 Activity 中创建 ServiceHandler,则会出现内存泄漏,因为 ServiceHandler 是在 Activity 中实例化的匿名类,因此引用了外部 Activity 实例。为了避免这种情况,您可以使用 Application 类作为上下文来调用 bindService()unbindService()
  2. 服务是业务逻辑,因此您最好不要将绑定(bind)服务的逻辑放入 View 层( Activity )中,而是放入其自己的“业务逻辑”组件中,即我们将此组件称为 MyServiceInteractor
  3. 当您在业务逻辑中移动该部分时,您可能想知道何时解除绑定(bind)/停止服务。在您的代码中,您已在 Presenter detachView() 中完成了该操作。虽然这有效,但 Presenter 现在对业务逻辑内部结构及其工作原理有了一些明确的了解。一个更类似于 Rx 的解决方案是将服务连接的生命周期与 Rx Observable 的“生命周期”联系起来。这意味着,一旦取消订阅/处置可观察对象,就应该关闭服务连接。这也与 1.“演示者在屏幕方向变化中幸存”(并在屏幕方向变化期间保持可观察的订阅处于 Activity 状态)完美匹配。
  4. 使用 Observable.create() 可以轻松地将任何回调/监听器“包装”到 Rx Observable 中。
  5. 我个人认为服务(尤其是有界服务)使用起来很麻烦,并且会给代码带来更高的复杂性。如果没有服务,您可能(或可能无法)实现相同的目标。但这实际上取决于您的具体应用/用例。

话虽如此,让我们看看可能的解决方案是什么样的(伪类似代码,可能无法编译):

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 世界的桥梁,并在可观察 get 取消订阅时停止服务连接。请注意,此代码 fragment 可能无法编译。这只是为了说明可能的解决方案/工作流程的样子。

那么您的 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 具体的,主要是我们如何将 android 服务回调“包装”到 RxJava 可观察中。一旦我们有了这个,剩下的就很容易了。

唯一与 MVI 相关的事情是连接点: View 实际上必须触发启动服务连接的 Intent 。这是通过 myView.startLoadingIntent()

bindIntents() 中完成的

希望对您有所帮助。

关于Android Mosby MVI 绑定(bind)到演示者中的服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43042785/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com