您的位置:首页 > 运维架构 > 网站架构

android系统架构MVP案例分析

2016-09-30 15:49 274 查看

前言

首先我们应该避免上帝类,上帝类(比如无所不能的Activity)的维护成本很高,你很难理解正在进行的操作,并且难以测试和扩展,这就是为什么要避免创建上帝类的黄金法则。在Android开发中,如果不考虑架构的话,Activity类往往会越来越大,最大的问题就是在Activity中同时存在业务逻辑和UI逻辑,这会增加测试和维护的成本。

目前流行的开发架构有MVC、MVP、MVVM等,起先使用比较多的是MVC,但也会有很多问题,Android中经常会出现数千行的Activity代码,究其原因,Android中纯粹作为View的各个XML视图功能太弱,Activity基本上都是View和Controller的合体,既要负责视图的显示又要加入控制逻辑,承担的功能过多,代码量大也就不足为奇。所有更贴切的目前常规的开发说应该是View-Model 模式,大部分都是通过Activity的协调,连接,和处理逻辑的。

现重点说明下MVP架构:



- View: 对应于Activity、Fragment和xml,负责View的绘制以及与用户交互;

- Model: 依然是实体模型;它区别于mvc架构中的Model,在这里不仅仅只是数据模型。在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。

- Presenter: 负责完成View与Model间的交互和业务逻辑。在MVP中model和view无法直接进行交换。

MVP目前使用的较多,利用MVP的设计模型可以把部分的逻辑的代码从Fragment和Activity业务的逻辑移出来,在Presenter中持有View(Activity或者Fragment)的引用,然后在Presenter调用View暴露的接口对视图进行操作,这样有利于把视图操作和业务逻辑分开来。MVP能够让Activity成为真正的View而不是View和Control的合体,Activity只做UI相关的事。

至于再后来衍生的MVVM,是目前比较推荐使用的方法:

View: 对应于Activity和xml,负责View的绘制以及与用户交互;

Model: 实体模型;

ViewModel: 负责完成View于Model间的交互,负责业务逻辑。

MVVM的目标和思想与MVP类似,利用数据绑定(Data Binding)、依赖属性(Dependency Property)、命令(Command)、路由事件(Routed Event)等新特性,打造了一个更加灵活高效的架构。具体请看这里:如何构建Android MVVM应用程序

事实上这几种框架没有谁比谁好,要视具体项目而选择。

Android官方MVP结构解读请移步:链接

认清Android框架MVC,MVP和MVVM

项目结构

我这里以实现一个天气为案例。先看下结构:



View:负责处理用户事件和视图部分的展示,它可能是Activity或者Fragment类。这里为:WeatherActivity。

Model:负责访问数据,数据可以是远端的ServerAPI,本地数据库或者SharedPreference等。这里为WeatherInfo。

Presenter:是链接(或者适配)View和Model的桥梁。这里为WeatherPresenter。

首先看View层,xml比较简单,就不显示了,WeatherActivity的源码如下:

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.chinaso.testandroid.R;
import com.victor.loading.rotate.RotateLoading;

public class WeatherActivity extends AppCompatActivity implements WeatherContract.View{
private TextView weatherInfoTV;
private RotateLoading rotateloading;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.weather_layout);

initView();
WeatherPresenter presenter = new WeatherPresenter(this, new WeatherDataSourece());
presenter.loadWeather();
}

private void initView() {
weatherInfoTV = (TextView)findViewById(R.id.weatherInfoTV);
rotateloading = (RotateLoading)findViewById(R.id.rotateloading);
}

@Override
public void setPresenter(WeatherContract.Presenter presenter) {

}

@Override
public void showLoadingIndicator(boolean isLoading) {

}

@Override
public void showWeatherDetail(WeatherInfo info) {
weatherInfoTV.setText(info.toString());
}

@Override
public void showLoading() {
rotateloading.setVisibility(View.VISIBLE);
rotateloading.start();
weatherInfoTV.setVisibility(View.GONE);
}

@Override
public void hideLoading() {
rotateloading.setVisibility(View.GONE);
rotateloading.stop();
weatherInfoTV.setVisibility(View.VISIBLE);
}

@Override
public void showNoContent() {
weatherInfoTV.setText("暂无数据");
rotateloading.setVisibility(View.GONE);
}
}


Model层为实体类WeatherInfo。这个比较简单,就不显示了。我这里使用的字段有:

private String cityStr;
private String weatherStr;
private String tempStr;
private String minIconStr;
//set,get


Presenter层为WeatherPresenter,源码如下:

public class WeatherPresenter implements WeatherContract.Presenter {

private WeatherContract.View mView;
private WeatherDataSourece mData;

public WeatherPresenter(WeatherContract.View view, WeatherDataSourece data) {
this.mView = view;
this.mData = data;
mView.setPresenter(this);
}
@Override
public void loadWeather() {
mView.showLoading();
mData.fetchWeather(new WeatherDataSourece.LoadWeatherCallback() {
@Override
public void onLoaded(WeatherInfo info) {
mView.hideLoading();
mView.showLoadingIndicator(false);
if (info == null){
mView.showNoContent();
} else {
mView.showWeatherDetail(info);
}
}

@Override
public void onDataNotAvailable() {
mView.showNoContent();
}
});
}
}


Presenter的接口如下:

public interface WeatherContract {
interface View {
void setPresenter(Presenter presenter);
void showLoadingIndicator(boolean isLoading);
void showWeatherDetail(WeatherInfo info);
void showLoading();
void hideLoading();
void showNoContent();
}

interface Presenter {
void loadWeather();
}
}


其它使用到的有:

网络请求数据类WeatherDataSource:

() {
@Override
public void onResponse(String response) {
if (!TextUtils.isEmpty(response)) {
Gson gson = new Gson();
WeatherInfo bean = gson.fromJson(response, WeatherInfo.class);
try {
callback.onLoaded(bean);
}catch (Exception e){}
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onDataNotAvailable();
}
});
VolleyRequestManager.getRequestQueue().add(request);
}
}
}" data-snippet-id="ext.9c00cb644ca271606aed657fbb8b175f" data-snippet-saved="false" data-codota-status="done">[code]import android.text.TextUtils;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.chinaso.testandroid.VolleyRequestManager;
import com.google.gson.Gson;

public class WeatherDataSourece {
private final String weatherURL = "xxx";
public interface LoadWeatherCallback {
void onLoaded(WeatherInfo info);
void onDataNotAvailable();
}

public void fetchWeather(final LoadWeatherCallback callback) {
if (weatherURL == null) {
callback.onDataNotAvailable();
} else {
StringRequest request = new StringRequest(weatherURL, new com.android.volley.Response.Listener<String>() {
@Override
public void onResponse(String response) {
if (!TextUtils.isEmpty(response)) {
Gson gson = new Gson();
WeatherInfo bean = gson.fromJson(response, WeatherInfo.class);
try {
callback.onLoaded(bean);
}catch (Exception e){}
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onDataNotAvailable();
}
});
VolleyRequestManager.getRequestQueue().add(request);
}
}
}


网络请求VolleyRequestManager:

初始化最好在Application.onCreate()下:

VolleyRequestManager.init(this);

import android.content.Context;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

public class VolleyRequestManager {
private static RequestQueue mRequestQueue;

private VolleyRequestManager() {
}

public static void init(Context context) {
mRequestQueue = Volley.newRequestQueue(context);
}

public static RequestQueue getRequestQueue() {
if (mRequestQueue != null) {
return mRequestQueue;
} else {
throw new IllegalStateException("Not initialized");
}
}
}


这样就可以解耦了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 系统架构 mvp