Android开发中MVP模式

传统的开发模式mvc大家都很熟悉。
在这里插入图片描述

View负责页面展示,Model负责数据。 Controller一个控制协调前两者的关系,很常见,耦合关系也很明显。

在常见的android应用开发中Activity类可以是非常复杂的代码集合,里面有各种view,事件,网络请求,数据bean。关联关系错综复杂。对代码复用,修改,重构产生了阻碍。

之后又有了MVP,MVVM(双向绑定)。
在这里插入图片描述

在MVC 中M/V之间存在耦合性,通俗的说就是充当V角色的类中有M角色类的导入和使用。降低耦合性就意味着代码之间要创造出更多的距离感,M和V互相没有直接的关系,却能各自通过P协同安排完成功能。更近一步,替换V,或者替换M只需要更小的范围内处理。

在CSDN上看到很多人针对android提出了各自的MVP的写法,大多是根据业务创建接口IBusiness,然后让Activity实现这个业务接口。 再创建一个Presenter类,在其中有IBusiness的成员变量。Activity中创建Presenter成员变量,通过Presenter调用指定业务方法,最终回调实现了IBusiness的Activity。 首先你会感觉这样写代码比以前要复杂了。某个页面的功能可能非常多,且在开发中易变性。接口虽然做到了一定的隔离,但是易变性带来的开发繁杂也不容小觑。

最近思考这个开发模式,自己总结了一套东西和大家分享。是不是可以把业务抽象成一项工作任务。 行为和行为的最终承受者。 行为可以是一段代码,指向固定的操作,比如请求网络获取数据,发送短信倒计时。。。。而承受者就是一个View。 比如请求一个列表数据是一项动作。 请求成功后的结果承受者是一个ListView或者RecyclerView. View 应该是具体数据无感,而对数据类型有感,意思就是ListView接受List<?> 而不是List《Dog》,List《Person》. TextView接受String类型作用于自己的setText. 而不需要知道Dog.getName. Person.getName; Button接受View.OnClickListener.而不管里面是什么动作,好比一个函数指针。

说了这么多来个例子。今天我们要实现的是一个定时改变TextView字符的需求。

首先是一个动作类。postValue就是传递结果数据。Handler每隔一秒传递一次数据。这个类没有跟任何View关联。

public class CountDownWork extends BaseViewModel {

    int count  = 0;
    private Handler handler  = new Handler();

    public CountDownWork(@NonNull Application application) {
        super(application);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        postValue("我是中欧人");
        new android.os.Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                postValue(Tools.concatAll("我是中欧人",java.lang.String.valueOf(count++)));
                handler.postDelayed(this,1000);
            }
        },1000);
    }

}

TestWorkActivity就是我们的试验场。UseLayout代替了setContentView。这个不用管。 enTrustWork是WorkProviderActivity中的方法,作用是提交一个工作单元,这里将动作和动作的承受者绑定完毕。

@UseLayout(layoutRes = R.layout.activity_test_provider)
public class TestWorkActivity extends WorkProviderActivity {

    @Override
    public void collectionWork() {
        enTrustWork(new WortUnit(CountDownWork.class,R.id.test_tv));
    }
}

可以看出我们实现一个业务,提炼与View无关的部分代码在BaseViewModel子类中。而这个子类是可以直接复用在其他的Activity中。而Activity中则会很清爽,不涉及业务接口,只要管理好自己的View树展现,并在collectionWork方法中,将自己的View 与动作绑定。

下面简单贴下源代码

工作单元。涉及工作内容和工作结果数据的承受者。

public class WortUnit {
    private Class<? extends BaseViewModel> baseViewModel;
    private int viewId;

    public Class<? extends BaseViewModel> getBaseViewModel() {
        return baseViewModel;
    }

    public void setBaseViewModel(Class<? extends BaseViewModel> baseViewModel) {
        this.baseViewModel = baseViewModel;
    }

    public int getViewId() {
        return viewId;
    }

    public void setViewId(int viewId) {
        this.viewId = viewId;
    }

    public WortUnit(Class<? extends BaseViewModel> baseViewModel, int viewId) {
        this.baseViewModel = baseViewModel;
        this.viewId = viewId;
    }
}

WorkProviderActivity类


public   class WorkProviderActivity extends FragmentActivity {

    private List<BaseViewModel> baseViewModels = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        UseLayout layout = this.getClass().getAnnotation(UseLayout.class);
        int layoutRes = 0;
        if (layout != null) {
            layoutRes = layout.layoutRes();
            setContentView(layoutRes);
        }
        collectionWork();
    }

    public  void collectionWork(){
    }

    public void enTrustWork( WortUnit... works){
        if(works!=null && works.length>0){
            for(WortUnit wortUnit:works){
                Class<? extends BaseViewModel> type =  wortUnit.getBaseViewModel();
                if(!baseViewModels.contains(type)){
                    BaseViewModel  baseViewModel = ViewModelProviders.of(this).get(type);
                    baseViewModel.setTtsActivity(this);
                    baseViewModels.add(baseViewModel);

                }
            }


        }

    }






}

BaseViewModel借助了android 中LiveData,AndroidViewModel ,LifecycleObserver,实现了数据与View的变更通知,组件生命周期方法调用。

public class BaseViewModel extends AndroidViewModel implements LifecycleObserver {
    // 创建LiveData
    private MutableLiveData<Object> data = new MutableLiveData<>();
    private WorkProviderActivity ttsActivity;
    private View view;

    private int viewId =View.NO_ID;

    public int getWorkerId() {
        return viewId;
    }

    public void setViewId(int viewId) {
        this.viewId = viewId;
    }

    public BaseViewModel(@NonNull Application application) {
        super(application);
    }

    public WorkProviderActivity getTtsActivity() {
        return ttsActivity;
    }

    public void setTtsActivity(WorkProviderActivity ttsActivity) {
        this.ttsActivity = ttsActivity;
        ttsActivity.getLifecycle().addObserver(this);

    }

    public void setAccount(Object object) {
        data.setValue(object);
    }

    public MutableLiveData<Object> getData() {

        return data;
    }


    @Override
    protected void onCleared() {
        super.onCleared();
    }


    @OnLifecycleEvent(value = Lifecycle.Event.ON_STOP)
    public void onStop() {


    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_START)
    public void onStart() {


    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_CREATE)
    public void onCreate() {

        int viewId = getWorkerId();
        if (viewId == View.NO_ID) {
            AppointWorker appointWorker = this.getClass().getAnnotation(AppointWorker.class);
            if (appointWorker != null) {
                viewId = appointWorker.value();
            }
        }
        if (viewId == View.NO_ID) {
            throw new RuntimeException("请指定工作者的id");
        }
        view = getTtsActivity().findViewById(getWorkerId());
        data.observe(getTtsActivity(), new Observer<Object>() {
            @Override
            public void onChanged(@Nullable Object t) {
                Action2 action2 = IntelligentActions.get(view, t);
                if (action2 != null) {
                    action2.call(view, t);

                }
            }
        });

    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_RESUME)
    public void onResume() {


    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_PAUSE)
    public void onPause() {

    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {


    }


    public void postValue(Object value) {
        data.postValue(value);
    }

    public void setValue(Object value) {

        data.setValue(value);
    }

}

关键在于这个data.observe操作,在postValue时候,会触发onChanged。IntelligentActions充当一个智能的判断数据和View之间应该擦出什么样的火花。比如TextView与String 优先是TextView.setText(String) …

data.observe(getTtsActivity(), new Observer<Object>() {
            @Override
            public void onChanged(@Nullable Object t) {
                Action2 action2 = IntelligentActions.get(view, t);
                if (action2 != null) {
                    action2.call(view, t);

                }
            }
        });
package rx.functions;

/**
 * A two-argument action.
 * @param <T1> the first argument type
 * @param <T2> the second argument type
 */
public interface Action2<T1, T2> extends Action {
    void call(T1 t1, T2 t2);
}

IntelligentActions预先保存View与数据类型应该做的操作,现在只添加了一些基本的。后续在开发中要添加适配,以及增加用户定制的优先级适配规则。

public class IntelligentActions {
    private static HashMap<Class<?>,HashMap<Class<?>,Action2>>actions  = new HashMap();

    public static<T1,T2> Action2<T1,T2> get(T1 view,T2 data){
        HashMap<Class<?>,Action2> action2HashMap =  actions.get(view.getClass());
        Action2 action2 =null;
        if(action2HashMap!=null){
            action2 =  action2HashMap.get(data.getClass());
            if(action2==null) {
                Set<Class<?>> classSet = action2HashMap.keySet();
                for (Class<?> type : classSet) {
                    if (type.isAssignableFrom(view.getClass())) {
                        action2 = action2HashMap.get(type);
                        break;

                    }

                }

            }
        }else{
            action2HashMap =  actions.get(data.getClass());
            if(action2HashMap!=null){
                action2 =  action2HashMap.get(view.getClass());
                if(action2==null) {
                    Set<Class<?>> classSet = action2HashMap.keySet();
                    for (Class<?> type : classSet) {
                        if (type.isAssignableFrom(view.getClass())) {
                            action2 = action2HashMap.get(type);
                            break;

                        }

                    }

                }
            }

        }
        return action2;


    }

    static {
        //全部View 用的click事件
        Action2<View,View.OnClickListener> onClickListenerAction= new Action2<View, View.OnClickListener>() {
            @Override
            public void call(View view, View.OnClickListener onClickListener) {
                view.setOnClickListener(onClickListener);
            }
        };
        HashMap<Class<?>,Action2> clickMap = new HashMap<>();
        clickMap.put(View.OnClickListener.class,onClickListenerAction);
        actions.put(View.OnClickListener.class,clickMap);

        //Textiew和其子类的setText
        HashMap<Class<?>,Action2> textViewMap = new HashMap<>();
        textViewMap.put(String.class, new Action2<TextView,String>() {
            @Override
            public void call(TextView textView, String o2) {
                textView.setText(o2);
            }
        });
        actions.put(TextView.class,textViewMap);

    }
}

在开发模式道路上的一次简单尝试。后续要在工作中不断完善框架。

猜你喜欢

转载自blog.csdn.net/atxxiang4/article/details/85778923