@RitcheeQinG
2020-08-31T07:21:22.000000Z
字数 7999
阅读 515
Android
四层架构:
使用mvvm的优点在哪:
缺点:
使用时的注意事项:
View层:
处理UI相关的逻辑,比如假设DataBean里面有一个String,那我们就可以把它设置给TextView,或者弹一个Toast,或者处理一些失败逻辑。
public class MainActivity extends AppCompatActivity() {private MainPageViewModel mMainPageViewModel;public void onCreate(Bundle savedInstanceState) {mMainPageViewModel = ViewModelProviders.of(this, null).get(MainPageViewModel.class);mMainPageViewModel.pageData.observe(this, new Observer<PageDataBean>() {@Overridepublic void onChanged(PageDataBean pageDataBean) {// ..}});mMainPageViewModel.queryData();}}
ViewModel层:
在这层我们在从DAO拿到数据模型以后,可以做一些UI无关,但可能和持久化相关的工作。
比如写入文件,写入SP,做一些这样类似的工作。
/*** 这里引一段Google官方的注释,还是挺有说服力的* ViewModel is a class that is responsible for preparing and managing the data for* an {@link android.app.Activity Activity} or a {@link androidx.fragment.app.Fragment Fragment}.* It also handles the communication of the Activity / Fragment with the rest of the application* (e.g. calling the business logic classes).* <p>* A ViewModel is always created in association with a scope (an fragment or an activity) and will* be retained as long as the scope is alive. E.g. if it is an Activity, until it is* finished.* <p>* In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a* configuration change (e.g. rotation). The new instance of the owner will just re-connected to the* existing ViewModel.* <p>* The purpose of the ViewModel is to acquire and keep the information that is necessary for an* Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the* ViewModel. ViewModels usually expose this information via {@link LiveData} or Android Data* Binding. You can also use any observability construct from you favorite framework.* <p>* ViewModel's only responsibility is to manage the data for the UI. It <b>should never</b> access* your view hierarchy or hold a reference back to the Activity or the Fragment.* <p>* Typical usage from an Activity standpoint would be:* <pre>* public class UserActivity extends Activity {** {@literal @}Override* protected void onCreate(Bundle savedInstanceState) {* super.onCreate(savedInstanceState);* setContentView(R.layout.user_activity_layout);* final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);* viewModel.userLiveData.observer(this, new Observer<User>() {* {@literal @}Override* public void onChanged(@Nullable User data) {* // update ui.* }* });* findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {* {@literal @}Override* public void onClick(View v) {* viewModel.doAction();* }* });* }* }* </pre>** ViewModel would be:* <pre>* public class UserModel extends ViewModel {* private final MutableLiveData<User> userLiveData = new MutableLiveData<>();** public LiveData<User> getUser() {* return userLiveData;* }** public UserModel() {* // trigger user load.* }** void doAction() {* // depending on the action, do necessary business logic calls and update the* // userLiveData.* }* }* </pre>** <p>* ViewModels can also be used as a communication layer between different Fragments of an Activity.* Each Fragment can acquire the ViewModel using the same key via their Activity. This allows* communication between Fragments in a de-coupled fashion such that they never need to talk to* the other Fragment directly.* <pre>* public class MyFragment extends Fragment {* public void onStart() {* UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);* }* }* </pre>* </>*/public class MainPageViewModel extends ViewModel {// 这里我们泛型里定义的数据模型可以是服务器传回来的,也可以是自定义的。// 一般来说,修改的不太频繁的话,用服务器的即可// 理论上自定义一个来实现可能更好一些public MutableLiveData<UserInfoModel> userInfoData = new MutableLiveData<>();public MutableLiveData<PageDataBean> mainPageData = new MutableLiveData<>();private MainPageDAO mainPageDAO;public void setMainPageDAO(MainPageDAO mainPageDAO) {this.mainPageDAO = mainPageDAO;}public void queryData() {mainPageDAO.queryData(new RequestResultListener<PageDataBean>() {@Overridepublic void onResponse(PageDataBean data) {mainPageData.postValue(data);}});}public void getUserInfo() {mainPageDAO.getUserInfoModel(new RequestResultListener<UserInfoModel>() {@Overridepublic void onResponse(UserInfoModel data) {// 如果有一些持久化相关的逻辑,可以在类似这里做// 比如: if (null != data)// SharedPreferens.get().save(data) 之类的userInfoData.setValue(data);}});}public static class MainPageViewModelFactory implements ViewModelProvider.Factory {private static MainPageViewModelFactory instance;// DAO层依赖private MainPageDAO mainPageDAO;// DO层依赖private IDomainObject<HealthTipBean> healthTipDO;/*** 一般实现都应该是懒加载的,按需使用*/public static MainPageViewModelFactory getInstance() {if (null == instance) {instance = new MainPageViewModelFactory();}return instance;}private MainPageViewModelFactory() {}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (null == healthTipDO) {healthTipDO = new HealthTipDO();}if (null == mainPageDAO) {mainPageDAO = new MainPageDAO();mainPageDAO.setHealthTipDO(healthTipDO);}try {T viewModel = modelClass.newInstance();modelClass.getMethod("setMainPageDAO", MainPageDAO.class).invoke(viewModel, mainPageDAO);return viewModel;} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);}}}}
DAO层:
理论上应该直接访问接口并把结果返回,不包含额外的工作。
public class MainPageDAO {// 理想情况下DO能自动注入进来就好了private IDomainObject<UserInfoModel> userInfoDOprivate IDomainObject<PageDataBean> dataBeanDO;public void queryData(RequestResultListener<PageDataBean> listener) {Map<String, Object> map = new HashMap<>();map.put("userId", "Q.R");healthTipDO.requestData(map, listener);}public void getUserInfoModel(RequestResultListener<UserInfoModel> listener) {userInfoDO.requestData(null, listener);}// ... setter 方法}
DO层:
这层到底是否需要其实还有待商榷,但是其存在的好处是能把DAO层的工作进一步拆分,提高复用性。
public class MainPageDO implements IDomainObject<PageDataBean> {@Overridepublic void requestData(Map<String, Object> paraMap, RequestResultListener<PageDataBean> listener) {OkManager.getInstance().post("url", paraMap, new OkManager.OkManagerStringListner() {@Overridepublic void onResponseString(String string, Integer target, Map<String, Object> resultParams) {PageDataBean pageDataBean = JsonTools.toObject(string, PageDataBean.class);if (null != listener) {listener.onResponse(pageDataBean);}}});}@Overridepublic void insertData(PageDataBean data, InsertCallback listener) {}}
DO层接口:
import java.util.Map;public interface IDomainObject<T> {void requestData(Map<String, Object> paraMap, RequestResultListener<T> listener);void insertData(T data, InsertCallback listener);}
回调接口:
请求返回的回调(无论是操作数据库还是API还是SP之类的)
public interface RequestResultListener<T> {void onResponse(T data);}
插入数据的回调
public interface InsertCallback {void onSuccess(Object object);void onFailed(Exception e, String message);}
既然MVVM涉及到状态信息,那么状态和生命周期自然是息息相关的,如果对每个Activity的每个生命周期,都按需去调用ViewModel的方法,未免太麻烦,在这里我设想了一个思路:
首先我们提供生命周期接口:
public interface ActivityLifeCycle {void onActivityCreate();void onActivityResumed();...}
然后我们整一个ViewModel基类,实现接口:
public class AbstractActivityViewModel implements ActivityLifeCycle {}
在BaseActivity里面则有方法:
public class BaseActivity extends AppCompatActivity {// ...public AbstractActivityViewModel getViewModel() {return this.mViewModel;}}
最后在 Application 中:
ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {@Overridepublic void onActivityCreated(Activity activity, Bundle savedInstanceState) {if (activity instanceof BaseActivity) {(BaseActivity) activity.getViewModel().onActivityCreate();}}// 此处省略其他周期@Overridepublic void onActivityDestroyed(Activity activity) {if (activity instanceof BaseActivity) {(BaseActivity) activity.getViewModel().onActivityDestroyed();}}};
也许有更好的代码,这里仅提供一个思路,以及,这里省略了一些判空之类的逻辑。