美文网首页
从没有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