美文网首页MVP
一个简单的mvp框架

一个简单的mvp框架

作者: 沉迷学习_日渐发福 | 来源:发表于2018-11-12 15:37 被阅读43次

    android中的各种框架

    在主流的开发框架中,目前比较流行的框架有MVC,MVP,MVVM框架。

    MVC

    MVC框架算是比较常见的一种开发框架了,即模型-视图-控制器,model用来存储数据,view来做界面的显示与绘制,控制器用来处理逻辑,处理Model和View之间的交互,当然view和model之间还有交互,view可以直接从model类存取数据,model也能够直接改变view的显示。

    优点-缺点:

    相较于没有框架来说,有了部分解耦,把业务逻辑和展示逻辑区分开,但是仍然耦合严重,在android中,一个activity几乎担任了view和control的职责,和model耦合很重。

    MVP

    在android中,mvp框架应该是目前用的较为广泛的,即模型-视图-Present,对于android来说,视图就是activity或者fragment及view,而present完全负责了view和model的逻辑交互。view只负责UI显示,present通过接口的形式,将处理完的逻辑调用接口改变UI。而model和view之间完全解耦,没有任何交互。

    优点:

    mvp相较于mvc来说,对于view和model是完全解耦了,model只负责自身的数据处理,所有的逻辑处理的放在了present,大大减少了android中view的逻辑处理。因为解耦,所以整个项目结构会比较清晰,也比较易于维护。

    缺点

    这个是解耦的设计的通病,一旦解耦了,代码量就上去了,而且文件数添加特别多,对于每一次改动,我们都需要改动inteface和inteface所对应的实现,但是为了项目的维护,这个应该是值得的。

    MVVM

    这个是最近几年刚提出的框架,通过xml和java代码的自动生成,来实现数据源与view的绑定与监听。一旦数据发生改变,view也会相应的作出改变。这个要了解的话可以看看我之前的一篇文章。

    light-mvp框架的使用

    这个框架是我在项目开发中写的,自己觉得挺方便的,所以分享一下。下面来看看这个mvp框架的简单使用。项目入口:https://github.com/xiejinlong/lightMvp

    present

    首先创建相应业务的present,内部定义了相应View需要实现的接口,prensent通过这个接口来改变UI

     public class ExamPresent extends BasePresent {
          public interface InterA {
            void change();
          }
          
          @BindV
          InterA interA;
          .....
      }
    

    present需要添加@BindV注解,而且需要继承于BasePresent

    activity or fragment

    对于activity和fragment来说,实现绑定present的逻辑是一样的。

    //activity
    public class ExamActivity extends BaseActivity implement ExamPresent.InterA {
      
      ....
      @BindP
      ExamPresent present
      
      }
    
    //fragment
    public class ExamFragment extends BaseFragment implement ExamPresent.InterA {
      
      ....
      @BindP
      ExamPresent present
      
      }
    

    对于activity来说,需要实现BaseActivity,而fragment需要实现BaseFragment,然后需要实现对应的present指定的接口,最后通过@BindP注解相应的present,一旦完成了这两步,view和present就绑定了
    使用时,直接可以使用present.method()方式进行调用,无需再进行new实例和绑定解绑操作

    生命周期

    present生命周期随着fragment的oncreateView方法和activity的onCreate方法创建。 随着fragment的onDestoryView方法和activity的onDestory方法销毁。
    一个fragment和acitivty支持绑定多个present, 一个present实例只支持绑定一个view

    light-mvp实现原理

    注解绑定V和P

    先来看看两个注解的实现

    //BindP
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface BindP {
    
    }
    
    //BindV
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface BindV {
    
    }
    
    

    这两个注解并没有参数,仅仅只是标识了变量的类型,以便于我们在反射中取值与赋值。
    下面来看看activity绑定p的过程,fragment绑定p的过程基本类似。

     
     @SuppressWarnings("unchecked")
        public static void parasBindPresent(BaseMvpActivity activity) {
            Class clazz = activity.getClass();
        //遍历当前类以及其父类,看是否存在BindP注解
            while (!(clazz.equals(Object.class) )) {
                parasBindPresent(activity, clazz);
                clazz = clazz.getSuperclass();
            }
        }
    
       //绑定入口
        private static void parasBindPresent(BaseMvpActivity<BasePresent> activity, Class clazz) {
            //获取当前baseMvpActivity的成员变量,
         Field[] fields = clazz.getDeclaredFields();
            for (Field f : fields) {
                //遍历所有的成员变量,找到添加了BindP注解的成员
                if (f.isAnnotationPresent(BindP.class)) {
                    try {
                //获取Present的类型
                        Class<?> c = f.getType();
                //创建Present对象
                        Object t = c.newInstance();
                       
                f.setAccessible(true);
                //给activity中的present变量赋值为t,也就是我们刚创建出来的present对象
                        f.set(activity, t);
                
                //为了生命周期处理,需要对BasePresent和BaseMvpActivity互相引用
                //所有的BasePresent定义了attachView方法,
                        ((BasePresent) t).attachView(activity);
                //activity添加present
                        activity.addPresent((BasePresent) t);
                 //因为绑定是双向绑定,既然v已经绑定了p,那么接下来需要做的就是p绑定v
                        ParasBindVAnnotation.parasBindView(t, activity);
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    上面的代码无非就是通过反射,进行v绑定p,下面看看p绑定v

    public static void parasBindView(Object t, BaseMvpActivity activity) {
        //这个t就是上面创建出来present对象
            Field[] fields = t.getClass().getDeclaredFields();
            for (Field f : fields) {
            //遍历所有方法,寻找添加了BindV注解的变量
                if (f.isAnnotationPresent(BindV.class)) {
                    try {
                //对present对象中添加了BindV注解的变量赋值
                        f.setAccessible(true);
                        f.set(t, activity);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    这样,一个p和v的绑定就完成了,当然这个只是两个对象的绑定。我们还需要看看两个Base类的实现,以及这个注解绑定何时调用,何时解绑。

    
    public abstract class BaseMvpActivity<T extends BasePresent> extends GestureBaseActivity implements BaseView {
    
        private List<T> presentList = new CopyOnWriteArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ParasBindPAnnotation.parasBindPresent(this);
    
            for (T present : presentList) {
                if (present != null) {
                    present.onCreate(savedInstanceState);
                }
            }
        }
    
        @Override
        public void onStart() {
            super.onStart();
            for (T present : presentList) {
                if (present != null) {
                    present.onStart();
                }
            }
    
        }
    
        @Override
        public void onResume() {
            super.onResume();
            for (T present : presentList) {
                if (present != null) {
                    present.onResume();
                }
            }
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            for (T present : presentList) {
                if (present != null) {
                    present.onNewIntent(intent);
                }
            }
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            for (T present : presentList) {
                if (present != null) {
                    present.onSaveInstance(outState);
                }
            }
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            for (T present : presentList) {
                if (present != null) {
                    present.onRestart();
                }
            }
        }
    
        @Override
        public void onPause() {
            super.onPause();
            for (T present : presentList) {
                if (present != null) {
                    present.onPause();
                }
            }
        }
    
        @Override
        public void onStop() {
            super.onStop();
            for (T present : presentList) {
                if (present != null) {
                    present.onStop();
                }
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            for (T present : presentList) {
                if (present != null) {
                    present.onDestroy();
                    presentList.remove(present);
                }
            }
        }
    
        public void addPresent(T t) {
            if (t != null) {
                presentList.add(t);
            }
        }
    
    
    
        @Override
        public Context getCtx() {
            return this;
        }
    
        @Override
        public <T> LifecycleTransformer<T> bindUntilEve() {
            return bindUntilEvent(ActivityEvent.DESTROY);
        }
    }
    
    

    从这个BaseMvpActivity类中,我们能够知道,它内部维持了一个present列表,这就是为什么它能够同时绑定多个的原因。ParasBindPAnnotation.parasBindPresent调用是在activity的oncreate方法中调用,也就是activity在onCreate方法中进行的p和v的绑定,绑定的同时会将这个present添加到presentList中,然后在activity的生命周期中,都会回调present的相应的生命周期。然后在这个activity的onDestory中,也就是即将销毁时会进行解绑,调用present的onDestory方法,并从列表中移除。

    public class BasePresent {
    
        protected BaseView mvpView;
    
        public BasePresent() {
        }
    
        public void attachView(BaseView mvpView) {
            this.mvpView = mvpView;
        }
    
        public void detach() {
            this.mvpView = null;
        }
    
        public void onCreate(Bundle saveInstanceState) {
        }
    
        public void onResume() {
        }
    
        public void onNewIntent(Intent intent) {
        }
    
        public void onPause() {
        }
    
        public void onStart() {
        }
    
        public void onStop() {
        }
    
        public void onDestroy() {
            detach();
            ParasBindVAnnotation.detachView(this);
        }
    
    
        public void onRestart() {
        }
    
        public void onSaveInstance(Bundle state) {
        }
    
        public void onRestoreSavedInstance(Bundle saveInstance) {
        }
    }
    
    

    在这个BasePresent中,我们可以先看到attachView这个方法,这个方法是在paraseBindPAnatation中调用的,这个BaseMvp是一些通用的mvp需要的方法,也就是在BaseMvp已经实现好了的。然后在ondestory方法中,首先会执行detach方法,将这个mvpView置为null,然后通过注解移除自身对activity或者fragment的引用。

    public static void detachView(Object t) {
            Field[] fields = t.getClass().getDeclaredFields();
            for (Field f : fields) {
            //对这个BindV的注解,做清空操作,即赋值为null
                if (f.isAnnotationPresent(BindV.class)) {
                    try {
                        f.setAccessible(true);
                        f.set(t, null);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    这样,整个mvp的绑定与解绑的流程就走完了。觉得还可以的就给个star吧~

    相关文章

      网友评论

        本文标题:一个简单的mvp框架

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