在当下Android开发中一个合适的架构设计尤为重要,一个好的设计不仅可以减少我们的bug率,而且代码实现也更加的优雅。我们常见架构设计有MVC、MVP、MVVM,这三种都有各自的优缺点。所有我们需根据实际业务的需求来选择合适的架构。那么了解这些设计模式的特点是非常有必要的,下文将浅谈这些架构特点。还有如果当我们项目到达一定的规模后,对项目进行组件化、插件化也是有一定的必要性的,它可以减少项目的臃肿,对项目进行分层分模块架构,让项目更具有可扩展性。
1、MVC
MVC是(Model-View-Controller, 模型-视图-控制器)的缩写,是软件设计中的一种典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,往往在Android里Activity即充当了部分视图层又充当了控制层,大量的代码会写在Activity里,xml布局相当于视图层,model则只负责与数据交换例如网络请求、本地数据库、文件读写等,当activity业务量并不复杂的情况下,具有简单明了的效果,但是一旦业务量或者逻辑众多会导致activity过于臃肿。
MVC代码例子
-
Model层
public class LoginModel {
public UserInfoEntitylogin(String userName,String pwd){ //模拟网络请求
UserInfoEntity userInfoEntity=new UserInfoEntity();
userInfoEntity.setUserName("是takiku啊");
userInfoEntity.setAge(23);
userInfoEntity.setSex(1);
return userInfoEntity;
}
}
-
View层
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ll_userinfo"
android:visibility="gone"
android:layout_above="@+id/ll_login"
android:layout_marginBottom="100dp"
android:layout_centerHorizontal="true"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_username"
android:text="用户名:hhhh"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="年龄:23岁"
android:id="@+id/tv_age"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:id="@+id/tv_sex"
android:text="性别:男"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ll_login"
android:orientation="vertical"
android:layout_centerInParent="true">
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:id="@+id/et_account"
android:hint="账号"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"/>
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:id="@+id/et_pwd"
android:inputType="textPassword"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_login"
android:layout_marginTop="20dp"
android:layout_gravity="center_horizontal"
android:text="登录"/>
</LinearLayout>
</RelativeLayout>
-
Controller层
private void toLogin() {
if (check()){
UserInfoEntity userInfoEntity= loginModel.login(accountTv.getText().toString(),pwdTv.getText().toString());
if (userInfoEntity!=null){
showUi(userInfoEntity);
}
}
}
private void showUi(UserInfoEntity userInfoEntity) {
userInfoll.setVisibility(View.VISIBLE);
userNameTv.setText(userInfoEntity.getUserName());
ageTv.setText(userInfoEntity.getAge()+"岁");
if (userInfoEntity.getSex()==0){
sexTv.setText("性别:女");
}else {
sexTv.setText("性别:男");
}
}
2、MVP
使用MVC模式时当app业务越来越多的时,Activity或者Fragment里的代码就显得很臃肿了,大量的代码堆积在一个activity里,View层和Controller层就有一定的耦合,当业务调整时,修改起来会让人挺头疼的,而且由于更新操作是没有对activity周期进行绑定的也有可能出现空指针异常,例如当网络状态不佳的时候,用户打开一个页面非常慢此时用户点击返回,这时恰好网络请求回调好了进行UI更新, 但是此界面已经被销毁了,就很容易造成空指针异常。而MVP模式恰好解决了这一个痛点,M还是原来的M层 ,V变成了Activity或者fragment, View层只进行单一的UI操作,所有的逻辑操作放在P层,Presenter层是View和Model的桥梁,
MVP的核心思想:
MVP把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model。
MVP代码例子
-
MVP模式的基类封装
-
视图的基类
-
/**
* 视图基类 可以发一些业务相关的公共视图显示
*/
public interface IBaseView {
}
-
MVPActivity基类
/**
* author:chengwl
* Description: MVP的Activity基类
* Date:2019/6/5
*/
public abstract class BaseMvpActivity<P extends IPresenter> extends BaseActivity implements IBaseView {
protected P mPresenter;
protected abstract P createPresenter();
/**
* p 层最先要做的事情
*/
protected abstract void initPresenter();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
if (mPresenter == null) {
throw new NullPointerException("Presenter is null! Do you return null in createPresenter()?");
}
mPresenter.onMvpAttachView(this, savedInstanceState);
mPresenter.onMvpAttachContext(this);
initPresenter();
}
@Override
protected void onStart() {
super.onStart();
if (mPresenter != null) {
mPresenter.onMvpStart();
}
}
@Override
protected void onResume() {
super.onResume();
if (mPresenter != null) {
mPresenter.onMvpResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (mPresenter != null) {
mPresenter.onMvpPause();
}
}
@Override
protected void onStop() {
super.onStop();
if (mPresenter != null) {
mPresenter.onMvpStop();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mPresenter != null) {
mPresenter.onMvpSaveInstanceState(outState);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter.onMvpDetachView(false);
mPresenter.onMvpDestroy();
}
}
}
-
Presenter基本接口
/**
* author:chengwl
* Description: P层接口:定义P层生命周期与 V层同步
* Date:2019/6/5
*/
public interface IPresenter<V extends IBaseView> {
void onMvpAttachView(V view, Bundle savedInstanceState); //绑定View层
void onMvpSaveInstanceState(Bundle savedInstanceState);
void onMvpDetachView(boolean retainInstance); // 解绑View层 需要的时候进行绑定,不需要的时候进行解绑就可以了
void onMvpStart();
void onMvpResume();
void onMvpPause();
void onMvpStop();
void onMvpDestroy();
void onMvpAttachContext(Context context);
}
-
Presenter基类
/**
* P层基类:
* Presenter生命周期包装、View的绑定和解除,P层实现的基类
*/
public abstract class BasePresenter<V extends IBaseView> implements IPresenter<V> {
//View接口类型的软引用
protected Reference<V> mViewRef;
protected Reference<Context> mContextRef;
public void attachView(V view){
mViewRef=new SoftReference<V>(view);
}
protected V getView(){
return mViewRef.get();
}
public boolean isViewAttached(){
return mViewRef!=null&&mViewRef.get()!=null;
}
public void detachView(){
if (mViewRef!=null){
mViewRef.clear();
mViewRef=null;
}
if (mContextRef!=null){
mContextRef.clear();
mContextRef=null;
}
}
@Override
public void onMvpAttachView(V view, Bundle savedInstanceState) {
attachView(view);
}
@Override
public void onMvpStart() {
}
@Override
public void onMvpDetachView(boolean retainInstance) {
detachView();
}
@Override
public void onMvpResume() {
}
@Override
public void onMvpPause() {
}
@Override
public void onMvpStop() {
}
@Override
public void onMvpAttachContext(Context context) {
mContextRef=new SoftReference<>(context);
}
}
-
Model层
public class LoginModel {
public UserInfoEntitylogin(String userName,String pwd){ //模拟网络请求
UserInfoEntity userInfoEntity=new UserInfoEntity();
userInfoEntity.setUserName("是takiku啊");
userInfoEntity.setAge(23);
userInfoEntity.setSex(1);
return userInfoEntity;
}
}
-
View层
public class LoginMVPActivity extends BaseMvpActivity<LoginPresenter> implements ILoginView{
private EditText accountTv;
private EditText pwdTv;
private TextView userNameTv;
private TextView ageTv;
private TextView sexTv;
private Button loginBtn;
private LoginModel loginModel;
private LinearLayout userInfoll;
@Override
protected LoginPresenter createPresenter() {
return new LoginPresenter();
}
@Override
protected void initPresenter() {
}
@Override
protected void initView() {
accountTv=findViewById(R.id.et_account);
pwdTv=findViewById(R.id.et_pwd);
userInfoll=findViewById(R.id.ll_userinfo);
loginBtn=findViewById(R.id.btn_login);
userNameTv=findViewById(R.id.tv_username);
ageTv=findViewById(R.id.tv_age);
sexTv=findViewById(R.id.tv_sex);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
toLogin();
}
});
}
private void toLogin() {
mPresenter.login(accountTv.getText().toString(),pwdTv.getText().toString());
}
@Override
public void onDataSuccess(UserInfoEntity userInfoEntity) {
showUi(userInfoEntity);
}
private void showUi(UserInfoEntity userInfoEntity) {
userInfoll.setVisibility(View.VISIBLE);
userNameTv.setText(userInfoEntity.getUserName());
ageTv.setText(userInfoEntity.getAge()+"岁");
if (userInfoEntity.getSex()==0){
sexTv.setText("性别:女");
}else {
sexTv.setText("性别:男");
}
}
@Override
public void onDataFailed(int code, String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public int getLayoutId() {
return R.layout.activity_login;
}
}
-
Presenter层
public class LoginPresenter extends BasePresenter<ILoginView> {
private LoginModel loginModel;
public LoginPresenter(){
loginModel=new LoginModel();
}
@Override
public void onMvpSaveInstanceState(Bundle savedInstanceState) {
}
@Override
public void onMvpDestroy() {
}
public void login(String account,String pwd){
UserInfoEntity userInfoEntity= loginModel.login(account,pwd);
getView().onDataSuccess(userInfoEntity);
}
}
网友评论