美文网首页
从没有MVX到MVC到MVP - (4 - MVP2)

从没有MVX到MVC到MVP - (4 - MVP2)

作者: __无语__ | 来源:发表于2018-09-19 13:26 被阅读0次

    简单示例演示如何从自由写法改进到MVC再改进到MVP - 4 - MVP2


    上一篇: https://www.jianshu.com/p/aabe77839655 - 3 - MVP,MVP的写法


    另一种MVP2是啥样?
    这个模式我还真没找到相关的图,那就描述一下吧!

    上一篇中MVP的设计图是这样的:


    MVP.png

    这个MVP2跟他类似,但有两个区别:
    一个区别是在于上一篇中提到的:

    这(上)个MVP实现中,还是直接用Fragment实现了IView接口

    另外一个区别是:

    View不直接引用Presenter,而是通过接口

    这个设计中Fragment作为中介,实现了IView和IPresenter中的回调接口。

    先看Fragment和IView的分离:
    简单的说就是在Fragment的onCreateView方法中返回一个View,而这个View实现了IView接口。

    我们先看下IView::

    public interface IBaseView {
    
        View getRootView();
    
        Context getContext();
    }
    

    IBaseView是一个基础接口,具体的页面应该有自己的一个IView,比如:

    public interface IUserListView extends IBaseView {
    
        interface IListViewHandler {
            void onRefreshList(); // 重点:注意这个是连接View 和 Presenter的接口方法
        }
    
        void updateList(List<UserModel> userModels);
    
        void showLoading();
    
        void hideLoading();
    
        void setViewHandler(IListViewHandler handler);
    
        void setEmptyListText(String emptyListViewTextString);
    }
    

    而这个IUserListView的实现类是这样的:

    public class UserListView implements IUserListView {
    
        private ScrollChildSwipeRefreshLayout mRefreshLayout;
    
        private ListView mUserListView;
    
        private UserListAdapter mUserListAdapter;
    
        private IListViewHandler mListViewHandler; // 重点:没有引用 Presenter,而是实现了一个回调接口
    
        private View mEmptyView;
    
        private TextView mEmptyTextView;
    
        private View mRootView;
    
        private Context mContext;
    
        public UserListView(LayoutInflater layoutInflater, ViewGroup container) {
            mRootView = layoutInflater.inflate(getLayoutId(), container, false);
            mContext = mRootView.getContext();
            init(mRootView);
        }
    
        private int getLayoutId() {
            return R.layout.fragment_list;
        }
    
        protected void init(View rootView) {
            mRefreshLayout = rootView.findViewById(R.id.refresh_layout);
            mUserListView = rootView.findViewById(R.id.user_list_view);
            mUserListAdapter = new UserListAdapter(null);
            mUserListView.setAdapter(mUserListAdapter);
    
            mRefreshLayout.setScrollUpChild(mUserListView);
            mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    if (mListViewHandler != null) {
                        mListViewHandler.onRefreshList();
                    }
                }
            });
    
            mEmptyView = rootView.findViewById(R.id.empty_list_layout);
            mEmptyTextView = mEmptyView.findViewById(R.id.empty_list_text_view);
        }
    
    
        @Override
        public void updateList(List<UserModel> userModels) {
            hideLoading();
            mUserListAdapter.setUserModelList(userModels);
            mUserListAdapter.notifyDataSetChanged();
            Toast.makeText(getContext(), "Update UI", Toast.LENGTH_LONG).show();
        }
    
        @Override
        public void showLoading() {
            mRefreshLayout.setRefreshing(true);
        }
    
        @Override
        public void hideLoading() {
            mRefreshLayout.setRefreshing(false);
        }
    
        @Override
        public void setViewHandler(IListViewHandler handler) {
            mListViewHandler = handler;
        }
    
        @Override
        public void setEmptyListText(String emptyListViewTextString) {
            String emptyText = mContext.getResources().getString(R.string.empty_text, emptyListViewTextString);
            mEmptyTextView.setText(emptyText);
            mUserListView.setEmptyView(mEmptyView);
        }
    
        @Override
        public View getRootView() {
            return mRootView;
        }
    
        @Override
        public Context getContext() {
            if (mRootView == null) {
                return null;
            }
            return mRootView.getContext();
        }
    }
    

    再看Fragment的实现,一切都就清楚了。

    1. Fragment中实现了IListViewHandlerListUpdaterListener, 他们分别是IView 和 IPresenter 的回调。
    2. 当用户操作(比如下拉)时调用IListViewHandler的回调方法,此时执行到Fragment里面的代码,
    3. Fragment里面调用Presenter的方法执行数据交互
    4. 然后Presenter调用ListUpdaterListener的方法触发到Fragment里面的回调
    5. Fragment再调用IView的方法来完成UI更新

    这几步完成了IView和IPresenter的解耦。

    public class MVP2UserListFragment extends Fragment implements IUserListView.IListViewHandler,
            UserListPresenter.ListUpdaterListener, IMainPresenter.IFabListener {
    
        private IUserListView mListView;
    
        IUserListPresenter mPresenter;
    
        public MVP2UserListFragment() {
            super();
        }
    
        public static MVP2UserListFragment newInstance() {
            return new MVP2UserListFragment();
        }
    
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mPresenter = new UserListPresenter();
        }
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            mListView = new UserListView(inflater, container);
            mListView.setViewHandler(this);
            mListView.setEmptyListText(mPresenter.getEmptyListText());
            return mListView.getRootView();
        }
    
        @Override
        public void onResume() {
            super.onResume();
            mPresenter.registerListener(this);
        }
    
        @Override
        public void onPause() {
            super.onPause();
            mPresenter.unregisterListener(this);
        }
    
        @Override
        public void onRefreshList() {
            mListView.showLoading();
            mPresenter.loadList();
        }
    
        @Override
        public void updateList(List<UserModel> userModels) {
            mListView.hideLoading();
            mListView.updateList(userModels);
        }
    
        @Override
        public void onFabClicked() {
            mListView.showLoading();
            mPresenter.addUser();
        }
    }
    

    贴下IPresenter:

    public interface IUserListPresenter<T> extends IBasePresenter<T> {
    
        void loadList();
    
        void addUser();
    
        String getEmptyListText();
    }
    

    Presenter

    public class UserListPresenter extends BasePresenter<UserListPresenter.ListUpdaterListener> implements IUserListPresenter<UserListPresenter.ListUpdaterListener> {
    
        private List<UserModel> mUserModels;
    
        public UserListPresenter() {
        }
    
        public void loadList() {
            BackgroundThreadPoster.post(new Runnable() {
                @Override
                public void run() {
                    mUserModels = UserManager.callAPIToGetUserList();
                    updateUI(mUserModels);
                }
            });
        }
    
        public void addUser() {
            BackgroundThreadPoster.post(new Runnable() {
                @Override
                public void run() {
                    UserModel userModel = UserManager.addUser();
                    mUserModels.add(userModel);
                    updateUI(mUserModels);
                }
            });
        }
    
        @Override
        public String getEmptyListText() {
            return "MVP2 :: ";
        }
    
        private void updateUI(final List<UserModel> userModels) {
            MainThreadPoster.post(new Runnable() {
                @Override
                public void run() {
                    for (ListUpdaterListener listener : getListeners()) {
                        listener.updateList(userModels);
                    }
                }
            });
        }
    
        public interface ListUpdaterListener {
            void updateList(List<UserModel> userModels);
        }
    }
    

    具体代码详见:
    https://github.com/chinalwb/mvc_mvp_mvvm

    相关文章

      网友评论

          本文标题:从没有MVX到MVC到MVP - (4 - MVP2)

          本文链接:https://www.haomeiwen.com/subject/fvcinftx.html