MVX调研有话说

小序

随着开发框架的潮流影响,再加上组织上给予的压力。看来不得不迈出MVC君的守望之门了,仿佛一股热流向此处涌来,其实际上已然有好多前辈写下了大写的文章在等着我。此刻起只要好好了解一番,再弄一两个小Demo便可造就一片新的天地了,然后就可以在蓝天白云下沐浴在阳光下奔跑了,光想想还是有点小激动的。


MVC

1.1.介绍

Created with Raphaël 2.1.0 View View Controller Controller Model Model User尝试点击 触发点击事件 发起数据请求 处理数据完毕,反馈更新 User看到效果

1.2.还是介绍

以上介绍主要是绘制并介绍了MVC层与层之间的交互过程,下面具体整理下各个层的含义与作用域:

whowhatwhere
Model业务逻辑处理层数据源处理,网络加载,复杂算法
View界面显示层布局文件.xml
Controller控制器Activity、Fragment

1.3.潜在输出

  • 将内容显示以及业务逻辑处理分隔开来,模块职责划分明确,有利于代码维护;
  • 提升项目的可扩展性与维护性,并降低耦合度;
  • 对业务逻辑复杂且页面较多的项目更能提升MVC的优势;

1.4.承受伤害

  • View与Controller融合在一起。大多数人通过Activity/Fragment直接控制View内容的更新;
  • View完全依赖Model。忽略Controller的控制直接从Model获取数据;
  • View自己承担部分业务逻辑。Model失去可重用的业务逻辑处理;
  • Controller同时负责View与Model的任务处理。使得代码异常臃肿,显得较为混乱;

1.5.代码飘过

/**
 8. Controller
 */
public class MainActivity extends AppCompatActivity {

    // 文本
    private TextView mMainTv;
    // 按钮
    private Button mMainBtn;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    /**
     * View
     */
    private void initView() {
        this.mMainTv = (TextView) findViewById(R.id.main_tv);
        this.mMainBtn = (Button) findViewById(R.id.main_btn);

        mMainBtn.setOnClickListener(v -> {
                mMainTv.setText(getDateTimeStr());
        });
    }

    /**
     * Model
     *
     * @return 当前日期时间
     */
    private String getDateTimeStr() {
        Date curDate = new Date(System.currentTimeMillis());
        return SimpleDateFormat.getDateTimeInstance().format(curDate);
    }
}

以上代码只是简单实现按钮点击获取当前的时间,并赋值给文本显示。其主要是表现大多数停留在MVC的伙伴,都会以这样一个方式去创建模块的页面和功能。至少接触过的很多项目里是这样的,当然并没有反对的意思,因为只要合理分配也是极好的。这里更多的是为了鉴于这个类来比较:

  1. 清晰mvc再战android

MVP

2.1.介绍

Created with Raphaël 2.1.0 View View Presenter Presenter Model Model User尝试点击 触发点击事件 发起数据请求 处理数据完毕 反馈更新 User看到效果

2.2.依然是介绍

同理,以上介绍主要是绘制并介绍了MVP层与层之间的交互过程。其情节内容没有改动,因为一个功能的思想一样不受使用模式的影响。下面具体整理下各个层的含义与作用域:

whowhatwhere
Model数据处理层数据的检索,存储等操作
View界面显示层Activity、Fragment、布局文件.xml
Presenter层现器作为View与Model两者的中间枢纽,处理与用户交互的负责逻辑

2.3.潜在输出

  • View层与Model层完全分离,两者间的修改互不影响;
  • Presenter控制View与Model之间的交互,大大提升模型的使用效率;
  • Presenter可以被多个View绑定(MVC当中Controller服务多个View);
  • 可完全脱离用户接口实现单元测试;
  • 解决MVC当中Activity代码臃肿的问题;

2.4.承受伤害

  • 由于Presenter可以被多个View绑定,且如果与Presenter之间的交互现象过于频繁,一旦View需要变更,那么Presenter也需要变更从而影响Presenter的复用性;
  • 大量的View与Model的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难;

2.5.前期装备

啥?还有前期装备,这是要逆天嘛,还有这装备到底是什么。请恕我直言,如果前期没有辅助那必须吃力些呀,所以View有理由学会摆脱与Presenter的直接交互,继而通过View interface来配合View接受Presenter返回结果的处理。下面是前期装备属性:

  • 降低View与Presenter之间耦合度;
  • 方便进行单元测试,可绕过View直接定义类实现interface模拟View与Presenter之间的交互;

2.6.后期装备

啥?还有后期,这发育的也太狠了吧。请恕我直言,这装备我也还没用过。当然它的属性是很诱人的,满满的被动输出伤害有木有。其实际上就是前辈们挖掘出来的两种View模式,用于划分View与Presenter的任务内容,具体如下:

whowhat
PV(Passive View)View的UI元素委托给Presenter操作
SoC(Supervising Controller)View自己负责UI处理以及数据绑定

2.7.代码飘过

相信刚接触MVP模式也许会像我一样,摸不清构建顺序吧。因为项目比较紧急,且又急于尝试MVP的实现,我仅在项目里使用了MVP+XUtils3的框架。下面贴出的代码仅供参考。

  • 基础构建
public class BasePresenter<V> {

    public V mvpView;
    public Context mContext;

    public BasePresenter(Context context, V mvpView) {
        this.mContext = context;
        this.mvpView = mvpView;
    }

    public void detachView() {
        this.mvpView = null;
    }
}
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity {

    public P mvpPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mvpPresenter = createPresenter();
    }

    protected abstract P createPresenter();
}
public abstract class BaseFragment<P extends BasePresenter> extends Fragement {

    public P mvpPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mvpPresenter = createPresenter();
    }

    protected abstract P createPresenter();
}
  • 具体实现,这里以请求登录操作为例。View interfacePresenterActivity/Fragment(感觉顺些)
public interface LoginView {

    void userLoginSuccess(UserInfo userInfo);

    void userLoginFail(String failMsg);
}
public class LoginPresenter extends BasePresenter<LoginView> {

    public void loginUser(String account, String pwd) {
        UserLogin userLogin = new UserLogin();
        userLogin.Account = account;
        userLogin.Password = pwd;

        RequestParams params = new RequestParams(ApiConfig.USER_IP + ApiConfig.USER_LOGIN);
        params.setBodyContent(userLogin.toJSONString());

        // 请求结果需对mvpView判空处理
        x.http().post(params, new Callback.CommonCallback<UserInfo>() {

            @Override
            public void onSuccess(UserInfo model) {
                if (null == mvpView) return;
                if (model.getStatusCode() == 200) {
                    mvpView.userLoginSuccess(model.getData());
                } else {
                    mvpView.userLoginFail(model.getMessage());
                }
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                if (null == mvpView) return;
                mvpView.userLoginFail("请求出错/网络异常");
            }

            @Override
            public void onCancelled(CancelledException cex) {}

            @Override
            public void onFinished() {}
        });
    }
}
@ContentView(R.layout.activity_login)
public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView {

    @ViewInject(R.id.login_edt_id)
    private EditText mIdEdt;

    @ViewInject(R.id.login_edt_pwd)
    private EditText mPwdEdt;

    @Override
    protected LoginPresenter createPresenter() {
        return new LoginPresenter(this, this);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        x.view().inject(this);
    }

    @Event(value = {R.id.login_btn}, type = View.OnClickListener.class)
    private void onAppClick(View view) {
        String idStr = mIdEdt.getText().toString();
        String pwdStr = mPwdEdt.getText().toString();
        // 为了代码简洁些,判空等处理被舍弃了
        mvpPresenter.loginUser(idStr, pwdStr);
    }

    @Override
    public void userLoginSuccess(UserInfo userInfo) {
        // 登录成功,执行相应操作
    }

    @Override
    public void userLoginFail(String failMsg) {
        // 登录失败,Toast提示错误信息
    }
}

以上只是个人实践内容,其实际上还有很多与MVP结合使用的大写之作,推荐:

  1. MVP+Retrofit+RxJava
  2. MVP+Dagger2+RxJava+Retrofit2

MVVM

3.1.介绍

Created with Raphaël 2.1.0 View View ViewModel ViewModel Model Model User尝试点击 数据源绑定更新,触发点击事件 发起数据请求,更新数据源 User看到效果

3.2.当然还是介绍

以上绘制并介绍了MVVM层与层之间的交互过程,其左边描述View与数据源的绑定,即控件显示数据与绑定的对象数据同步更新(可以忽略时序图的前后顺序这一说,只怪提供的绘图方法有限)。下面具体整理下各个层的含义与作用域:

whowhatwhere
Model数据处理层数据的检索,存储等操作
View界面显示层Activity、Fragment、布局文件.xml
ViewModel视图模型可理解为View的Model和Presenter之间的融合

3.3.潜在输出

  • 数据捆绑UI更新。数据与业务逻辑处在一个独立的ViewModel当中,由数据主导UI的更新(eg. DataBinding框架实现被捆绑的UI更新)
  • 低耦合度。ViewModel不对View的任何控件保持持有状态,更改UI无需修改ViewModel的实现;
  • 团队协作。扮演UI处理以及数据和业务逻辑的两个不同角色;
  • 复用性强。同一个ViewModel可以为多个View服务;
  • 单元测试。只需要在ViewModel执行单元测试,完全不需要依赖View的任何操作;

3.4.承受伤害

  • 多个View与ViewModel执行捆绑,造成ViewModel比较笨重;
  • 数据对象的直接引用使得后期维护起来会比较困难;

3.5.这里木有代码

只是了解了下但还没有确切实践过MVVM,暂时也就没有代码飘过了


总结

4.1.共同点

whowhat
View一直扮演者与用户交互的角色
Model因数据处理而忙碌着

4.2.不同点

whowhat
Controller被动的负责将View的需求告知Model处理并让Model通知View更新
Presenter在Model前面拿下View的请求做一定的业务处理才给回Model做数据操作处理,
数据请求处理结束后再将Model数据返回给View并提示更新
ViewModel在Presenter的基础上绑定并实现了对View的部分数据操作


PS1.没有什么绝对好的开发模式,倘若没有规范好自身的代码,一切都将是空谈
PS2.以上内容若存在不足之处,还望大虾们指点一二

利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值