传统的开发模式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);
}
}
在开发模式道路上的一次简单尝试。后续要在工作中不断完善框架。