@RitcheeQinG
2020-08-31T07:21:22.000000Z
字数 7999
阅读 444
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>() {
@Override
public 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>() {
@Override
public void onResponse(PageDataBean data) {
mainPageData.postValue(data);
}
});
}
public void getUserInfo() {
mainPageDAO.getUserInfoModel(new RequestResultListener<UserInfoModel>() {
@Override
public 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
@Override
public <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> userInfoDO
private 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> {
@Override
public void requestData(Map<String, Object> paraMap, RequestResultListener<PageDataBean> listener) {
OkManager.getInstance().post("url", paraMap, new OkManager.OkManagerStringListner() {
@Override
public void onResponseString(String string, Integer target, Map<String, Object> resultParams) {
PageDataBean pageDataBean = JsonTools.toObject(string, PageDataBean.class);
if (null != listener) {
listener.onResponse(pageDataBean);
}
}
});
}
@Override
public 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() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity instanceof BaseActivity) {
(BaseActivity) activity.getViewModel().onActivityCreate();
}
}
// 此处省略其他周期
@Override
public void onActivityDestroyed(Activity activity) {
if (activity instanceof BaseActivity) {
(BaseActivity) activity.getViewModel().onActivityDestroyed();
}
}
};
也许有更好的代码,这里仅提供一个思路,以及,这里省略了一些判空之类的逻辑。