Android架构组件:用ViewModelCommandLiveData处理ViewModel中的事件发布

如果你已经开始使用Google官方的Mvvm框架,理想情况下,Activity或者Fragment当中的逻辑应该越少越好,然而事实上我们的页面在加载layout,获取Viewmodel之外,往往还负责着以下一些职责:

  • 各种对话框(等待效果,确认,Toast等等)
  • 页面跳转
  • 其他页面需要监控viewmodel变化的行为

尽管DataBinding解决了数据->视图绑定的问题,仍然有一些操作是我们必须在Activity/Fragment当中完成的,这些不得不由视图完成的行为可以视为一系列CallBack,现在的问题是,如何将这些CallBack从ViewModel中分发出去。

Mvp中如何解决Callback问题

MVP模式下,会约定一个约束类,来要求View跟Presenter分别负责自己的行为:

public interface BaseMVPContract {
    interface View extends BaseView {
        /**
         * 开始等待加载
         */
        void onLoadingStart();

        /**
         * 结束等待加载
         */
        void onLoadingEnd();
    }

    interface Presenter extends Presenter<View> {
        /**
         * 加载ProjectList
         *
         * @param parentId 父分类id
         * @param name     分类名称
         */
        void loadProjects(Long Id);

    }
}
复制代码

在Mvvm中,ViewModel不关心View的实现,也不持有View的引用,因此,对View的约束没有存在的必要,参考LiveData的使用,我们可以考虑将Viewmodel要求视图执行的指令封装成一个被观察者(LiveData),将动作发布出去,视图方订阅这个LiveData来实现自己的指令执行逻辑.

封装指令LiveData的一种实现方式

public class ViewModelCommandLiveData<T> {
    private MutableLiveData<List<UiAction<T>>> delegate = new MutableLiveData<>();

    private List<UiAction<T>> list = new ArrayList<>();

    @MainThread
    public void execute(@NonNull UiAction<T> action) {
        list.add(action);
        delegate.setValue(list);
        //一个指令的状态是瞬时的,因此在执行完成之后需要清除状态
        delegate.setValue(null);
    }

    public void observe(LifecycleOwner owner, @NonNull UiActionExecutor<T> executor) {
        delegate.observe(owner, uiActions -> {
            if (uiActions != null) {
                for (UiAction<T> action : uiActions) {
                    executor.exec(action);
                }
            }
            if (uiActions != null && !uiActions.isEmpty()) {
                list = new ArrayList<>();
            }
        });
    }

    public interface UiAction<E> {
        void exec(E t);
    }

    public interface UiActionExecutor<R> {
        void exec(UiAction<R> action);
    }
}
复制代码
ViewModel中如何发送指令
public class ProjectListViewModel extends AndroidViewModel {
    //指令LiveData
    public ViewModelCommandLiveData<ProjectListVmHandler> commands = new ViewModelCommandLiveData<>();

    public LiveData<List<Project>> getProjectList(String userId) {
        //发送指令开始等待效果
        commands.execute(t->t.onLoadingStart());
        final MutableLiveData<List<Project>> data = new MutableLiveData<>();

        gitHubService.getProjectList(userId).enqueue(new Callback<List<Project>>() {
            @Override
            public void onResponse(Call<List<Project>> call, Response<List<Project>> response) {
                //发送指令关闭等待效果
                commands.execute(t->t.onLoadingEnd());
                data.setValue(response.body());
            }

            @Override
            public void onFailure(Call<List<Project>> call, Throwable t) {
                //发送指令关闭等待效果
                commands.execute(t->t.onLoadingEnd());
                data.setValue(null);
            }
        });

        return data;
    }


    public interface ProjectListVmHandler{
        void onLoadingStart();
        void onLoadingEnd();
    }
}
复制代码
视图中订阅指令并实现指令处理:
public class ProjectListFragment extends Fragment implements Injectable {
    public static final String TAG = "ProjectListFragment";

    @Inject
    ViewModelProvider.Factory viewModelFactory;
    private ProjectListViewModel.ProjectListVmHandler mHandler = new ProjectListViewModel.ProjectListVmHandler() {
        @Override
        public void onLoadingStart() {
            showLoading();
        }

        @Override
        public void onLoadingEnd() {
            hideLoading();
        }
    };

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        final ProjectListViewModel viewModel = ViewModelProviders.of(this,
                viewModelFactory).get(ProjectListViewModel.class);

        observeViewModel(viewModel);
    }

    private void observeViewModel(ProjectListViewModel viewModel) {
        //订阅viewModel指令LiveData
        viewModel.commands.observe(this, action -> action.exec(mHandler));
    }

}
复制代码

总结

关于ViewModel中是否需要CallBack的话题,不同的业务场景有不同的回答,作为一个程序员,我们总是希望把UI相关的重复、繁琐又容易出bug的套路代码交给代码生成去处理,但是实际业务场景往往需要我们这样去做,本文的VMCommandLiveData作为一个解决思路,希望能起到抛砖引玉的作用。

转载于:https://juejin.im/post/5b1749f36fb9a01e4b061f2e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值