关于MVP模式集成框架

3 篇文章 0 订阅
1 篇文章 0 订阅

MVPFrame

一个基于MVP开发框架代码库,MVPFrame由model、view、presenter、data 4部分组成,并且将view、presenter向上提取,
封装成基类,子类只需要继承基类使用即可,不用定义接口使用。

MVP组成


Presenter

负责View与Model之间的交互和数据通信,这是Presenter定义与实现

public interface IPresenter {

     /**
      * Presenter被初始化时调用
      *
      * @param view Activity对象
      */
     void attachView(View view);

     /**
      * Activity被销毁时调用
      * {@link Activity#onDestroy()}
      */
     void detachView();
}

/**
 * 普通页面使用的Presenter
 * Created by huang on 2017/2/7.
 */
public class BasePresenter implements IPresenter {

    private View view;

    protected View getView() {
        return view;
    }

    @Override
    public void attachView(View view) {
        this.view = view;
    }

    @Override
    public void detachView() {
        view = null;
    }
}

View

主要负责UI交互,通过initView、initData、initListener、newPresenter初始化,注newPresenter只能被调用一次,
需要保证View中presenter对象不变。openLoadingAnim和closeLoadingAnim是进行有延时操作时对Loading效果的控制。
onModelComplete(ModelResult) 是Model处理数据的结果回调方法

public interface View<P extends BasePresenter> {

    /**
     * 初始化视图
     */
    void initView();

    /**
     * 初始化数据
     */
    void initData();

    /**
     * 初始化监听
     */
    void initListener();

    /**
     * 创建Presenter
     *
     * @return IPresenter实现类
     */
    P newPresenter();

    /**
     * 打开加载动画
     */
    void openLoadingAnim();

    /**
     * 关闭加载动画
     */
    void closeLoadingAnim();

    /**
     * Model加载数据完成回调方法
     *
     * @param result 返回结果
     */
    void onModelComplete(ModelResult result);
}

Activity的基类实现,将View嵌入到Activity中。获取Presenter对象不是通过newPresenter()方法,而是getPresenter()
方法。通过ResultAnalysis类将Model返回结果ModelResult进行解析,并调用handleError()方法处理错误结果。

public abstract class MvpActivity<P extends BasePresenter> extends AppCompatActivity implements View<P> {

   ...

    /**
     * 初始化Presenter并关联Activity
     *
     * @return presenter
     */
    protected P getPresenter() {
        if (presenter == null) {
            presenter = newPresenter();
            if (presenter != null) {
                presenter.attachView(this);
            }
        }
        return presenter;
    }

    @Override
    public void onModelComplete(ModelResult result) {
        result.analysis(new ResultAnalysis.DefResultAnalysis() {

            @Override
            public void fail(int reqCode, ModelException e) {
                handleError(e);
            }
        });
    }

    /**
     * Model错误处理
     *
     * @param e 异常
     */
    protected abstract void handleError(ModelException e);

}

    ...
    @Override
    protected void handleError(ModelException e) {
            switch (e.getErrorType()) {
                case ModelException.ERROR_NET_NONE:
                    break;
                case ModelException.ERROR_NET_UNSTABLE:
                    break;
                case ModelException.ERROR_NET_SERVER:
                    break;
                case ModelException.ERROR_IO_CACHE:
                    break;
                case ModelException.ERROR_IO_LOCAL:
                    break;
            }
    }

Model

数据处理,例如获取网络数据、IO数据。并将获取数据通过Presenter传递给View
例如:

public class ListModel {

    public void onRefresh(final int resultCode, RequestParam param, final ResultCallback callback) {
        final ArrayList<ListData> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            list.add(new ListData(i, "标题 " + i));
        }
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                ModelResult result = new ModelResult(resultCode);
                Bundle bundle = new Bundle();
                bundle.putParcelableArrayList("result", list);
                result.setBundle(bundle);
                callback.onComplete(result);
            }
        }, 500);
    }

    public void commit(int resultCode, MultiLogic logic, ResultCallback callback) {
        StringBuilder builder = new StringBuilder();
        List<IAdapter> select = logic.getSelectItems();
        for (IAdapter item : select) {
            ListItem listItem = (ListItem) item;
            builder.append(listItem.getItemPosition());
        }
        ModelResult result = new ModelResult(resultCode);
        Bundle bundle = new Bundle();
        bundle.putString("ids", builder.toString());
        result.setBundle(bundle);
        callback.onComplete(result);
    }
}

Data

数据模型,默认实现Parcelable接口。
定义Data的意义在于,再打包时,数据模型类不能被混淆,这时就可以
-keep class * implements com.kisen.mvplib.bean.Data{*;}

增加对列表的mvp实现


其实list(RecyclerView、ListView)、Adapter、Model、Data。同样是mvp的体现,也可以使用mvp框架去实现。
这里以RecyclerView为例(RecyclerView灵活,依赖少,可拓展性强,效果也很棒,建议大家使用)

Adapter

一般我们在写列表界面时都会写很多Adapter,代码重复,无非就是onBindViewHolder(),getItemViewType(),getItemCount()
和onCreateViewHolder()方法,我们可以将这几个方法的实现转移到Data数据类中,这样我们定义IAdapter接口:

public interface IAdapter {

    /**
     * 需要实现,返回对应Item的布局文件Id 如果返回0,则使用适配器默认布局
     *
     * @return 返回当前数据类对应布局
     */
    int getItemResId();

    /**
     * 必须实现,在数据类中直接将数据适配到通过BaseViewHolder获取到的视图中
     *
     * @param helper          用来获取Item的控件
     * @param adapterPosition 该Item在Adapter中的位置
     *                        {@link android.widget.BaseAdapter#getView(int, View, ViewGroup)}
     */
    void onBindViewHolder(BaseViewHolder helper, int adapterPosition);

    /**
     * 需要实现,默认返回0,同一列表中出现多种不同的布局时,必须返回不同的类型,
     * 如果返回相同的值,会因BaseViewHolder复用出现布局错乱,处理数据时异常
     * 在{@link IAdapter#getItemResId()}中已经把对应的布局返回给适配器
     *
     * @return 返回当前自定义Item类型
     * {@link android.widget.BaseAdapter#getItemViewType(int)}
     */
    int getItemType();

    /**
     * 在Adapter中获取到的Item的位置数据
     *
     * @return item在adapter中的位置
     */
    int getItemPosition();
}

自定义Adapter,利用IAdapter将逻辑转移到Data中:

public class BaseAdapter<I extends IAdapter> extends RecyclerView.Adapter<BaseViewHolder> {

    private List<I> mItems;
    private int itemPos;

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(mItems.get(itemPos).getItemResId(), parent, false);
        return new BaseViewHolder(v);
    }

    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        itemPos = holder.getAdapterPosition();
        mItems.get(position).onBindViewHolder(holder, position);
    }

    @Override
    public int getItemViewType(int position) {
        return mItems.get(position).getItemType();
    }

    @Override
    public int getItemCount() {
        return mItems == null ? 0 : mItems.size();
    }

    ...
}

这样我们就可以避免XXXAdapter,只需要一个BaseAdapter就够了,如果有特殊要求也可以重新实现。
在Data中我们就可以把逻辑处理好。

public class UserData implements IAdapter {

    private int pos;
    private String name;
    private String pwd;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public int getItemResId() {
        return 0;
    }

    @Override
    public void onBindViewHolder(BaseViewHolder helper, int adapterPosition) {
        pos = adapterPosition;
    }

    @Override
    public int getItemType() {
        return 0;
    }

    @Override
    public int getItemPosition() {
        return pos;
    }
}

Item实现

但是这样又会带来一个问题:数据类一般是由网络请求得到的,不会添加过多的类引用(例如:Context上下文,逻辑处理对象等)
这样就会导致局限性,当我们有更多需求时,在这种方式下,处理数据类逻辑会更复杂,而数据类本身代码量也会随着处理逻辑的
增加而增加。所以我们不使用数据类实现IAdapter,我们单独定义一个Item类实现IAdapter,并且增加相应的API:

public abstract class Item<D extends Data> implements IAdapter, Interact<D>, View.OnClickListener {

    protected D data;
    protected ItemLogic logic;
    protected BaseAdapter adapter;
    protected int position;
    protected Context mContext;

    @Override
    public void onBindViewHolder(BaseViewHolder helper, int adapterPosition) {
        position = adapterPosition;
        setViewData(helper);
        helper.itemView.setEnabled(itemEnable());
        helper.itemView.setOnClickListener(this);
        onRefreshViewStyle();
    }

    @Override
    public int getItemType() {
        //默认返回 0,可重写
        return 0;
    }

    @Override
    public int getItemPosition() {
        return position;
    }

    @Override
    public void onClick(View v) {
        if (logic != null && logic.isReady()) {
            logic.onItemClick(adapter, this);
        }
        onItemClick(v);
    }

    /**
     * 返回Item持有数据
     */
    public D getData() {
        return data;
    }

    /**
     * 设置处理逻辑
     */
    public void setLogic(ItemLogic logic) {
        this.logic = logic;
    }

    /**
     * 给Item设置数据
     */
    public void setData(D data) {
        this.data = data;
    }

    /**
     * 设置Adapter
     */
    public void setAdapter(BaseAdapter adapter) {
        this.adapter = adapter;
    }

    /**
     * 设置上下文
     */
    public void setContext(Context context) {
        mContext = context;
    }
}

Item类还是实现了Interact接口,Interact接口主要是一些Item的交互与逻辑

public interface Interact<D extends Data> {
    /**
     * 用于更新UI样式
     */
    void onRefreshViewStyle();

    /**
     * 得到Data数据,显示在Item上
     *
     * @param helper item UI持有对象
     * @see IAdapter setViewData(Context context,BaseViewHolder helper, int adapterPosition)
     */
    void setViewData(BaseViewHolder helper);

    /**
     * 设置Item是否可以点击
     */
    boolean itemEnable();

    /**
     * 条目点击事件。
     * {@link Interact#itemEnable()}必须返回true,这个方法才会被调用
     *
     * @param v item对应View
     */
    void onItemClick(View v);

    /**
     * 工厂方法创建Item时调用的方法
     *
     * @return 返回一个新的Item实例
     */
    Item<D> newSelf();

    /**
     * Item被创建时,设置完数据后调用,
     * 在{@link Item#onBindViewHolder(BaseViewHolder, int)}之前被调用,
     * 只被调用一次
     */
    void readyTodo();
}

到目前为止列表的MVP框架已经建好了。View(Adapter)、Presenter(Item)。
大家可能又在想Item与Data对IAdapter的实现,比较这两种方式,感觉Item没有很大优势?
现在我有这样一个需求:在一个列表中,实现Item多选,并返回选择的结果。
那我们继续:

/**
 * 列表Presenter
 * <p>
 * 绑定{@link ItemLogic}列表逻辑处理
 * 生成默认BaseAdapter
 * 使用ItemFactory生成Item列表
 * </p>
 * Created by huang on 2017/2/7.
 */
public abstract class BaseListPresenter<D extends Data> extends BasePresenter {

    private Item<D> mItemTemplate;
    private ItemFactory<D> factory;
    protected ItemLogic itemLogic;
    private BaseAdapter<Item<D>> adapter;

    @Override
    public void attachView(View view) {
        super.attachView(view);
        mItemTemplate = setupItemTemplate();
        adapter = new BaseAdapter<>();
        factory = new ItemFactory<>(view, mItemTemplate, adapter);
    }

    /**
     * 在父类中注册ItemLogic,
     * 主要是在创建Item时传给所有Item,保持所有Item都持有一个ItemLogic对象
     * {@link ItemFactory#makeItems(List, ItemLogic)}
     *
     * @param logic 在父类中注册的ItemLogic
     */
    protected void setItemLogic(ItemLogic logic) {
        itemLogic = logic;
    }

    @Override
    public void detachView() {
        super.detachView();
        if (itemLogic != null) {
            itemLogic.clear();
            itemLogic = null;
        }
        mItemTemplate = null;
        factory = null;
        adapter.clear();
    }

    /**
     * 通过list生产出Item列表
     * {@link ItemFactory#makeItems(List, ItemLogic)}
     *
     * @param list 生产Item所需数据源
     */
    public void notifyAfterLoad(List<D> list) {
        List<Item<D>> items = factory.makeItems(list, itemLogic);
        adapter.addData(items);
    }

    public BaseAdapter<Item<D>> getAdapter() {
        return adapter;
    }

    /**
     * 设置Item模板用于生产列表
     * {@link Item#newSelf()}
     *
     * @return 一个Item模板
     */
    protected abstract Item<D> setupItemTemplate();
}

现在又增加了一个ItemLogic类,在BaseListPresenter中有一个ItemFactory工厂类,每一个Item都会持有ItemLogic对象,
我们通过ItemLogic实现Item之间的逻辑交互。说到这里,我们这个开发框架介绍完了。相对于Google提供的有关mvp的Demo,
类的数量就少了很多,这里我们提取了View、Presenter、BaseAdapter、Item,这样我们在使用时,普通页面只需要创建四个类
:Activity、Model、Presenter、Data,而列表界面就比较多了,需要创建六各类:Activity、ListPresenter、
Item、Model、Logic(如果不需要,可以不创建,而且可以重复使用,与Item是解耦和的)、Data;

项目地址

https://github.com/Huang102/MVPFrame

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值