您的位置:首页 > 移动开发

Android APP架构的那点事儿[MVP架构搭建]

2016-02-28 11:40 489 查看
接上篇《APP架构的那点事儿[网络模块]》

完成了网络模块,那么我们是不是该进入MVP主体架构的开发了,当然,有些朋友会说:“难道一定要先写网络模块,就不能先做架构主体么!” 这个随意了,看个人喜好,有话好好说嘛,把砖头放下.



所谓的mvp,个人理解为model层处理业务逻辑(主要是数据读写、与服务器端通信(其实也是读写数据));view层处理ui显示(通常包含Activity、Fragment、View (应该如何选择));presenter层为指示器,应该说包含很多个Presenter组成,作为中间件操作相对应的model和view)

具体MVP细节,感兴趣的朋友搜下,很多!

如何下手开发?其实我们可以从一个简单的功能点入手,然后其他功能照着模子继续造轮子就行。下面简单一个获取城市列表的例子。



Model层

/**
* 城市对象模型
* Created by liaonaibo on 16/2/14.
*/
public class City extends BaseResource{
/**城市ID*/
public int id;
/**省份名称*/
public String province;
/**城市*/
public String city;
/**城市/区名称*/
public String district;

public City(){
this.dataType = DataType.DT_List_City_Weather;
}

public static List<City> parserList(String json){
try {
JSONObject obj = new JSONObject(json);
String data = obj.optString("result");
if (!TextUtils.isEmpty(data)) {
List<City> list = new Gson().fromJson(data,
new TypeToken<List<City>>() {
}.getType());
return list;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}


Presenter层

/**
* 城市列表UI主持者
* 作为View与Model交互的中间纽带,处理与用户交互的负责逻辑
* Created by liaonaibo on 16/2/15.
*/
public class CityListPresenter {
private Context mContext;
private ICityListView mICityListView;
private boolean isLoading;
private List<BaseResource> mData;
public CityListPresenter(Context context,ICityListView iCityListView){
this.mContext = context;
this.mICityListView = iCityListView;
this.mData = new ArrayList<BaseResource>();
}

public void getData(){
if (isLoading){
return;
}
isLoading = true;
//通知UI数据加载中
mICityListView.onDataLoading();
NetworkController.getInstance(mContext).requestCityList(null, new NetworkRequestListener() {
@Override
public void response(String response) {
isLoading = false;

if(!TextUtils.isEmpty(response)){
List<City> list = City.parserList(response);
if(null != list && list.size() > 0){
mData.addAll(list);
//显示数据到UI上
mICityListView.showCityList(mData);
}else{
//没有数据了
mICityListView.requestDataFailByNoData();
}
}

}

@Override
public void error(int errorCode, String errorLog) {
isLoading = false;
//通知UI网络异常
mICityListView.requestDataFailByNetswork();
}
});
}

/**
* 跳转到天气详情界面
* @param view
*/
public void jumpToWeatherDetailActivity(View view) {
Object object = view.getTag();

if(null != object){
City city = (City) object;
WeatherDetailActivity.start(mContext, city);
}
}

/**
* 获取点击事件数组
* @return
*/
public View.OnClickListener[] getOnClickListeners() {
View.OnClickListener[]  listeners = new View.OnClickListener[1];
listeners[0] = new View.OnClickListener() {
@Override
public void onClick(View v) {
jumpToWeatherDetailActivity(v);
}
};
return listeners;
}

/**
* 搜索城市
* @param cityName
*/
public void searchCity(String cityName) {
City city = new City();
city.dataType = DataType.DT_List_City_Search;
city.city = cityName;
WeatherDetailActivity.start(mContext, city);
}
}


View层

个人总结,对于View所需定义的接口,可以通过产品功能上的入手,熟悉产品交互流程, 然后考虑:

该操作需要什么?(那些参数?)
该操作的结果,对应的反馈?(显示列表??showFailedError?)
该操作过程中对应的友好的交互?(加载中?加载完成?)


/**
* 城市列表View接口
* Created by liaonaibo on 16/2/15.
*/
public interface ICityListView {
/**显示城市列表*/
void showCityList(List<BaseResource> list);
/**数据加载中*/
void onDataLoading();
/**没有数据*/
void requestDataFailByNoData();
/**请求失败*/
void requestDataFailByNetswork();
}


/**
* 城市列表界面
*/
public class MainActivity extends FragmentActivity implements ICityListView, View.OnClickListener {

private CityAdapter mAdapter;
private ListView mListView;
private ProgressBar mProgressBar;
private EditText et_search;
private CityListPresenter mPresenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVariable();
initLayout();
loadData();
}

/**
* 初始化变量
*/
private void initVariable() {
mPresenter = new CityListPresenter(this, this);
}

/**
* 初始化布局
*/
private void initLayout() {
mListView = (ListView) findViewById(R.id.activity_main_lv);
mProgressBar = (ProgressBar) findViewById(R.id.activity_main_pb);
et_search = (EditText) findViewById(R.id.activity_main_et_search);

et_search.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
searchCity();
return true;
}
return false;
}
});

findViewById(R.id.activity_main_iv_search).setOnClickListener(this);
}

/**
* 加载数据
*/
private void loadData() {
//调用主持者获取数据
mPresenter.getData();
}

@Override
public void showCityList(List<BaseResource> list) {
mProgressBar.setVisibility(View.GONE);
if (null == mAdapter) {
mAdapter = new CityAdapter(this, mPresenter, list);
mListView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}

@Override
public void onDataLoading() {
//TODO:数据加载中
mProgressBar.setVisibility(View.VISIBLE);
}

@Override
public void requestDataFailByNoData() {
//TODO:没有数据了
mProgressBar.setVisibility(View.GONE);
Toast.makeText(this, "没有数据了,稍候重试", Toast.LENGTH_SHORT).show();
}

@Override
public void requestDataFailByNetswork() {
//网络异常
mProgressBar.setVisibility(View.GONE);
Toast.makeText(this, "网络异常,稍候重试", Toast.LENGTH_SHORT).show();
}

@Override
public void onClick(View v) {
int id = v.getId();
if (R.id.activity_main_iv_search == id) {
searchCity();
}
}

private void searchCity() {
String city = et_search.getText().toString();
if (TextUtils.isEmpty(city)) {
Toast.makeText(this, "请输入城市名称", Toast.LENGTH_SHORT).show();
return;
}
mPresenter.searchCity(city);
}
}


如何选择使用Activity、Fragment、View?

有朋友问,项目应该使用Activity还是Fragment还是View?首先我们要理解这三者的关系



解释一下,Fragment的英译是”碎片”,Fragment是Activity的封装部件,简单说Fragment要基于Activity才能显示,View也一样。当Activity太大,承载太多不同功能或类型的UI的时候,可以尝试拆分为独立的多个独立的Fragment(或View)来显示UI。而Activity和Fragment是有生命周期的结构使用两者,保持职责清晰,心里要有个概念,那就是单一原则。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息