Android MVC框架,个人见解

关于网上对mvc框架的介绍有很多,例子也很多。因为框架都是人用的,所以每个人都有每个人的见解。由于最近有大把的时间,巩固下基础和加深下理解【以下都是个人理解,可以借鉴,有自己的想法】

mvc的优点:很好的将model和view层分离,降低耦合,降低代码块之间相互影响,提高代码复用及扩展;

缺点是:如果完全按照mvc框架开发,有些地方会变得臃肿。而且view层和controller没有完全解耦


首先我觉得开发框架是为了更好的开发,最好是借鉴开发思路,灵活运用。比如,你封装了一个PreferenceUtil用来存储一些轻量的数据,这个时候存储只要调用PreferenceUtil.put就行了。这个时候完全按照mvc的话,意思要把数据处理这块放在model会显得比较多余,个人见解。

【View(视图层)】:

与用户交互,响应用户操作。可理解为,layout布局。同时activity里有view的引用,有些博客说model拿到数据交给view,有些又说交给controller,然后交给view。因为Activity既有Control又有View,所以Control和View有少量的耦合性;在这里我先将activiity在mvc中是定位成controller(控制器)的。只要知道Controller和View有这一层关系就可以了。

【Controller(控制器)】

响应用户操作,并通知model数据等处理

【Model(模型)】

Model接收Controller的通知后,独立运行,请求数据等,通过接口将数据返回

 

先发一个项目链接基于mvc的思路的封装

好多人把网络请求什么的封装在BaseActivity和BaseFragment,我个人觉得只是借鉴了mvc的思路,加入是dialog里要请求网络呢,而且封装在base里。BaseActivity和BaseFragment要写2遍了。所以这个时候要用一个Model将这部分独立出来像这样:

public abstract class ModelBase {
    //okhttp get请求
    public void sendOkHttpGet(final ParamsBuilder paramsBuilder, final NetWorkListener netWorkListener) {
        final Context context;
        if (netWorkListener instanceof AppCompatActivity) {
            context = (AppCompatActivity) netWorkListener;
        } else if (netWorkListener instanceof Fragment) {
            context = ((Fragment) netWorkListener).getActivity();
        } else {
            context = paramsBuilder.getContext();
        }

        String tag = paramsBuilder.getTag();
        if (TextUtils.isEmpty(tag)) {
            //不设置tag,默认用类路径名。
            tag = netWorkListener.getClass().toString();
        }
        EasyOk.get()
                .url(paramsBuilder.getUrl())
                .tag(tag)
                //内部已经做了null处理
                .headers(paramsBuilder.getHeads())
                //内部已经做了null处理
                .params(paramsBuilder.getParams())
                //默认不缓存
                .cacheOfflineTime(paramsBuilder.getCacheOfflineTime())
                .cacheOnlineTime(paramsBuilder.getCacheOnlineTime())
                //默认只请求一次
                .onlyOneNet(paramsBuilder.isOnlyOneNet())
                //默认不重连
                .tryAgainCount(paramsBuilder.getTryAgainCount())
                .build()
                .enqueue(new ResultCall() {
                    @Override
                    public void onBefore() {
                        if (paramsBuilder.isShowDialog()) {
                            if (context == null) {
                                throw new NullPointerException("context is null");
                            }
                            LoadingDialog.getInstance().show(context, paramsBuilder.getLoadMessage());
                        }
                    }

                    @Override
                    public void onAfter() {
                        LogUtils.i("我难道没有走吗", "11111111111");
                        LoadingDialog.getInstance().dismiss();
                    }

                    @Override
                    public void onError(String message) {
                        if (paramsBuilder.isOverrideError()) {
                            NetFailBean errorBean = new NetFailBean(message);
                            netWorkListener.onNetCallBack(paramsBuilder.getCommand(), errorBean);
                        } else {
                            // 不重写那么只弹提示
                            ToastUtils.showToast(message);
                        }

                    }

                    @Override
                    public void onSuccess(final String response) {
                        Type type = paramsBuilder.getType();
                        if (type == null) {
                            //如果type不带,那么返回string
                            EasyOk.getInstance().getmDelivery().post(new Runnable() {
                                @Override
                                public void run() {
                                    netWorkListener.onNetCallBack(paramsBuilder.getCommand(), response);
                                }
                            });
                            return;
                        }
                        Object successBean = null;
                        try {
                            successBean = GsonUtil.deser(response, type);
                        } catch (Exception e) {
                            LogUtils.i("网络请求", "解析出错了 ==> 参数类型可能有误");
                            return;
                        }
                        if (((ResponModel) successBean).getStatus() == 1) {
                            //我以前的接口定义的是1是成功,例如点关注,1关注成功,0关注失败。这里网络code都是200,注意
                            final Object finalSuccessBean1 = successBean;
                            EasyOk.getInstance().getmDelivery().post(new Runnable() {
                                @Override
                                public void run() {
                                    netWorkListener.onNetCallBack(paramsBuilder.getCommand(), ((ResponModel) finalSuccessBean1).getBody());
                                }
                            });

                        } else {
                            if (paramsBuilder.isSuccessErrorOverrid()) {
                                final Object finalSuccessBean = successBean;
                                EasyOk.getInstance().getmDelivery().post(new Runnable() {
                                    @Override
                                    public void run() {
                                        ErrorBean errorBean = new ErrorBean(((ResponModel) finalSuccessBean).getMessage());
                                        netWorkListener.onNetCallBack(paramsBuilder.getCommand(), errorBean);
                                    }
                                });
                            } else {
                                //不重写默认都是弹提示,考虑到用户有其他操作,可能不弹提示,有其他操作考虑
                                final Object finalSuccessBean2 = successBean;
                                EasyOk.getInstance().getmDelivery().post(new Runnable() {
                                    @Override
                                    public void run() {
                                        ToastUtils.showToast(((ResponModel) finalSuccessBean2).getMessage());
                                    }
                                });

                            }

                        }
                    }

                    @Override
                    public void inProgress(float progress) {

                    }
                });
    }
}

 

我用一个抽象类把具体的网络请求和解析封装起来了。网上大量讲解mvc的都说一个接口一个model,我在想如果这部分统一的代码都要在每个model了写一遍,真的会累死人了。同时每个接口一个model,接口量一大,我相信,你去找接口请求,和把网络请求写在controller没有多大区别 。

所以我的思路是:把统一操作用ModelBase封装起来,联网请求和数据分析。然后可以用一个单例把ModelSuperImpl把所有的需要联网请求调用的方法放进去,界面调用只需要传参数和网络请求结果回调即可:

public class ModelSuperImpl extends ModelBase {
    private static final ModelSuperImpl ourInstance = new ModelSuperImpl();

    public static ModelSuperImpl netWork() {
        return ourInstance;
    }

 
    private ModelSuperImpl() {

    }


    public void gankGet(ParamsBuilder paramsBuilder, NetWorkListener netWorkListener) {
        paramsBuilder.url(SystemConst.GANK_GET)
//                .type(new TypeToken<ResponModel<String>>() {
//                }.getType())
        ;
        sendOkHttpGet(paramsBuilder, netWorkListener);
    }
}

这样一个ModelSuperImpl就可以搞定,可以把所有网络请求调用方法放在这里面。也方便查找之类的。当然,假如我们有数据存储和权限申请,当然可以在写一个Model,将不同功能逻辑业务代码分割开还是有必要的,下面以权限申请为例,可以用ModelPermissionImpl去封装,如:

public class ModelPermissionImpl {
    //有可能一个页面进行多个网络请求,加上一个指令type区分
    public void requestPermission(final int permissionCommand, final FragmentActivity activity, final PermissionListener permissionListener, final String... permission) {
        //如果权限都被申请了,那么不再继续
        if (checkPermission(activity, permission)) {
            permissionListener.permissionSuccess(permissionCommand);
            return;
        }

        RxPermissions rxPermissions = new RxPermissions(activity);
        rxPermissions.request(permission).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Exception {
                if (aBoolean) {
                    //有些手机保持禁止以后会出现aBoolean为true的情况,则加上下一句
                    if (!checkPermission(activity, permission)) {
                        permissionListener.permissionFail(permissionCommand);
                        return;
                    }
                    permissionListener.permissionSuccess(permissionCommand);
                } else {
                    permissionListener.permissionFail(permissionCommand);
                }
            }
        });
    }


    public boolean checkPermission(Context context, String... permission) {
        for (int i = 0; i < permission.length; i++) {
            if (ActivityCompat.checkSelfPermission(context, permission[i]) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }
}

权限请求成功需要的实现的接口是PermissionListener;由于操作的方便性,我们也可以把ModelPermissionImpl的调用放进单例ModelSuperImpl里,这样调用起来,直接用一个类搞定,不会那么紊乱。像这样:

public class ModelSuperImpl extends ModelBase {
    private static final ModelSuperImpl ourInstance = new ModelSuperImpl();

    public static ModelSuperImpl netWork() {
        return ourInstance;
    }

    public static ModelPermissionImpl permission() {
        return new ModelPermissionImpl();
    }

    private ModelSuperImpl() {

    }
}

在你用到网络请求和权限申请的页面只需要实现接口NetWorkListener和PermissionListener;网络请求调用ModelSuperImpl.netWork.;权限申请调用ModelSuperImpl.permission.

以上大部分代码多余代码都去掉了,便于理解。这些观点都是我个人对mvc的一些见解。这个时候配合BaseActivity和BaseFragment实现网络回调接口更佳。如果理解有误,欢迎留言指正

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值