这几天学了一下子Android中常用的框架,感觉还是迷迷糊糊的先记录一下吧。
MVP架构是由Model、Presenter、View这三个组成。
Model表示模型,主要负责数据的加载;VIew表示视图主要负责视图绑定,界面的展示,界面逻辑跳转等;Presenter是表示器,主要作为View和Model的中间人,完成他们之间的交互,从而实现高内聚低耦合的思想。
下图是偷的B站大佬的视频截图(QAQ...)大概就是把数据获取和展示分开来做,使得代码结构清晰,易于维护。
但是一般实际项目中会在建立一个Contract,这又是什么鬼?
这就涉及到MVP的缺点了,正所谓,金无足赤,人无完人,MVP既然有优点当然也有它的缺点了
MVP在实现代码简洁的同时,额外增加了大量的接口、类,不方便进行管理,于是Contract就登场了。
Contract 百度翻译 : 合同;契约;协议
Contract 如其名,是一个契约,将Model、View、Presenter 进行约束管理,方便后期类的查找、维护。
基于MVP这个思想可以有很多的实现方式,上面展示的这个方式是Google官方提出的一种MVP实现方式。谷歌官方的MVP实现方式中,弱化了Model的作用,将Model融入到了Presenter中。本套代码也是仿照了Google的方式实现的(弱弱的小白虽然不懂,毕竟得抱紧大佬的腿嘛。。。)
以下代码来自大佬的Github,仰望。。。只是粘了比较重要的部分
代码结构:
MVP的结构是 MainActivity、MainContract、MainPresenter
MainContract:定义了接口规范
MainPresenter:具体代码逻辑的实现
MainActivity:
package com.chaochaow.weather;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.loopeer.cardstack.CardStackView;
import com.loopeer.cardstack.UpDownAnimatorAdapter;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity implements MainContract.View, CardStackView.ItemExpendListener {
MainPresenter presenter;
@BindView(R.id.stackview_main) //绑定控件 减少findviewbyId的使用
CardStackView mStackview;
WeatherStackAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//隐藏隐藏上面的ActionBar
getSupportActionBar().hide();
//设置窗体全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
ButterKnife.bind(this); //绑定控件
//MVP架构
presenter = new MainPresenter(this);
String[] cities = new String[]{"青岛", "绍兴", "成都", "武汉", "重庆", "南京", "天津", "苏州", "西安", "长沙", "沈阳",
"郑州", "大连", "宁波", "厦门", "福州", "无锡", "合肥", "昆明", "哈尔滨", "济南", "佛山", "长春", "温州"};
//从服务器获取天气数据 并且 调用setData实现UI更新
presenter.getData(cities);
}
@Override
public void setData(List weatherEntities) {
mAdapter = new WeatherStackAdapter(this);
mStackview.setAnimatorAdapter(new UpDownAnimatorAdapter(mStackview));
mStackview.setItemExpendListener(this);
mAdapter.setData(weatherEntities);
mStackview.setAdapter(mAdapter);
}
@Override
public void dataError(Throwable e) {
Toast.makeText(this,"加载失败...",Toast.LENGTH_LONG).show();
}
@Override
public void onItemExpend(boolean expend) {
}
}
MainContract:
package com.chaochaow.weather;
import java.util.List;
public interface MainContract {
interface View{
/**
* presenter获取数据后调用此方法将数据展示到界面上
* @param weatherEntities 获取到的天气数据
*/
void setData(List weatherEntities);
/**
* presenter获取数据失败调用此方法将错误信息展示到界面上
* @param e
*/
void dataError(Throwable e);
}
interface Presenter{
/**
* 从服务器获取天气数据
*/
void getData(String[] cities);
}
}
MainPresenter:RxJava2+Retrofit2网络请求部分
package com.chaochaow.weather;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* @author chaochaowu
* @Description : MVP框架中的presenter用来处理数据请求
* @class : MainPresenter
* @time Create at 5/28/2018 2:05 PM
*/
public class MainPresenter implements MainContract.Presenter{
MainContract.View mView;
public MainPresenter(MainContract.View mView) {
this.mView = mView;
}
@Override
public void getData(String[] cities) {
final List weatherEntities = new ArrayList<>();
Retrofit retrofit = new Retrofit.Builder() //网络请求
.baseUrl("https://free-api.heweather.com") //一个baseurl地址,网络请求的接口地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析的工具。geson
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
/*让retrofit返回一个Observable类型,用于之后rxjava相关操作。*/
.build();
WeatherService weatherService = retrofit.create(WeatherService.class);
for (String city : cities) {
weatherService.getWeather("0adc843380064d1c9c11ddf49de8----", city)
.subscribeOn(Schedulers.io())//subscribeOn方法声明请求是在io线程上执行
.observeOn(AndroidSchedulers.mainThread())//ObserveOn声明回调的操作是在UI线程上执行
.subscribe(new Observer() {//subscribe里定义的便是请求之后的操作
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(WeatherEntity weatherEntity) {
weatherEntities.add(weatherEntity);
}
@Override
public void onError(Throwable e) {
mView.dataError(e);
}
@Override
public void onComplete() {
mView.setData(weatherEntities);
}
});
}
}
}
WeatherService :retrofit2框架定义请求格式,根据要请求地址的API
package com.chaochaow.weather;
import io.reactivex.Observable;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface WeatherService {
/**
* 获取指定城市的天气信息
* @param key 开发者key
* @param location 城市名称
* @return 返回一个Observable类型 用于Rxjava的处理
*/
@GET("s6/weather/now")
Observable getWeather(@Query("key") String key, @Query("location") String location);
}