最近公司的项目也不是太紧了,之前有用过mvp但是感觉还是迷迷糊糊的,搞不懂为什么要这么设计,就知道mvp分别代表了什么含义,但是在实际的项目开发中还是懵的,最近看了大牛老师的博客,算是给自己一个更深刻的理解吧。我看的是老司机老师写的通过mvp设计模式实现的天气数据的加载案例。
说先创建了NowWeather.java类,分别有天气的情况,温度,风级和最后更新的时间四个字段;
public class NowWeather {
private String text;
private int temperature;
private double windcale;
// 数据更新时间(该城市的本地时间)
public Date lastUpdateDate;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getTemperature() {
return temperature;
}
public void setTemperature(int temperature) {
this.temperature = temperature;
}
public double getWindcale() {
return windcale;
}
public void setWindcale(double windcale) {
this.windcale = windcale;
}
public Date getLastUpdateDate() {
return lastUpdateDate;
}
public void setLastUpdateDate(Date lastUpdateDate) {
this.lastUpdateDate = lastUpdateDate;
}
@Override
public String toString() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
return text + "," + temperature + "摄氏度," + "风力为" + windcale + "级,更新时间为" + dateFormat.format(lastUpdateDate);
}
}
2.写Application,这个我们经常在写就不多说了,因为这个项目使用的是心知天气官网获取的key和用户id初始化WeatherManager,因此需要依赖一个jar包 thinkpage_sdk_v_1_0_1.jar,然后申请key和value,在Application中初始化。
public class MyApplication extends Application {
public static TPWeatherManager weatherManager;
@Override
public void onCreate() {
super.onCreate();
initWeather();
}
/**
* 初始化WeatherManager
*/
private void initWeather() {
weatherManager = TPWeatherManager.sharedWeatherManager();
//使用心知天气官网获取的key和用户id初始化WeatherManager
weatherManager.initWithKeyAndUserId("9qymisgxng5au4hu", "UE8440B558");
}
}
接着就需要分析一下了,我们的activity已经创建好了,我们最终要实现的是获取一个城市当天的天气,因此我们肯定需要定义一个方法来获取天气的情况,该方法是getWeatherState(),这个方法需要什么参数了,我们需要思考一下,获取天气情况到底是成功还是失败,我们得告诉客户端一个结果吧,因此我们需要定义一个接口来观察获取天气成功还是失败,该接口定义如下:
public interface WeatherListener{
void onSucess(TPWeatherNow tpWeatherNow);
void onFailed(String error);
}
这时候我们获取天气的这个类就可以写完整了,要获取某个城市的情况,只需要传入城市名和获取是否成功的监听即可了
package test.dmdfchina.com.weathermvptest.model;
import com.thinkpage.lib.api.TPCity;
import com.thinkpage.lib.api.TPListeners;
import com.thinkpage.lib.api.TPWeatherManager;
import com.thinkpage.lib.api.TPWeatherNow;
import test.dmdfchina.com.weathermvptest.MyApplication;
/**
* Created by mkt on 2018/1/16.
*/
public class WeatManagerUtil {
public static WeatManagerUtil instance = new WeatManagerUtil();
/*获取天气状态的接口*/
public interface WeatherListener {
void onSucess(TPWeatherNow tpWeatherNow);
void onFailed(String error);
}
/*定义获取指定城市的天气的方法*/
public void getWeatherState(String cityName, final WeatherListener weatherListener) {
扫描二维码关注公众号,回复:
8644670 查看本文章
MyApplication.weatherManager.getWeatherNow(new TPCity(cityName), TPWeatherManager.TPWeatherReportLanguage.kSimplifiedChinese, TPWeatherManager.TPTemperatureUnit.kCelsius, new TPListeners.TPWeatherNowListener() {
@Override
public void onTPWeatherNowAvailable(TPWeatherNow tpWeatherNow, String s) {
if (tpWeatherNow != null) {
weatherListener.onSucess(tpWeatherNow);
} else {
weatherListener.onFailed(s);
}
}
});
}
}
好,写好天气管理类之后,我们接下来就要写View和Presenter层了,View层该怎么写呢?View層只需要对控件初始化,但是为了更好的封装,将所有view共有的方法抽取出来,写成一个接口,只要所有的activity的View实现该接口就可以初始化控件了。
public interface IView {
void initView();
}
同理,Presenter也是同样的道理,
public interface IPresenter<V extends IView> {
void onStart();
void onResume();
void onPause();
void onStop();
void onDestroy();
void initView(V view);
}
presenter之所以这么设计,巧妙滴将presenter和activity的周期进行绑定,这样可以避免内存泄露。
好,我们已经将所有activity共有的类抽取出来,接下来我们就写mvp中的View和presenter了,要怎么写了,肯定我们刚才写的IView.java和IPresenter.java就该用上场了,只要让他实现我们刚才定义的两个接口就可以了,但是View和presenter之间是有一定的关系的,也就是说所有的逻辑部分是在Presenter和View层来实现的,而activity只是负责展示Presenter和 View处理后的结果,因此我们定义一个WeatherContract.java类,将View和Presenter关联起来。
/**
* Created by mkt on 2018/1/16.
* 将weatherView和presenter关联起来
*/
public class WeatherContract {
public interface IWeatherView extends IView{
void showWeatherState(NowWeather nowWeather);
void onError(String errorMsg);
}
/*获取城市对应的天气状况*/
public interface IweatherPresenter extends IPresenter<IWeatherView>{
void getWeather(String cityName);
}
}
到这里我有点蒙了,不是在WeatManagerUtil.java中已经定义了该方法了,怎么还要定义在Presenter中定义getWeather(String cityName)的方法了,因为我们要明白最后和activity打交道的是presenter,而不是WeatManagerUtil.java,或者你也可以理解为Presenter类是对获取天气方法的进一步实现。
好,写好了View层,即IWeatherView之后,我们来写Presenter层,首先要实现IWeatherPresenter.java接口,然后将IWeatherView的对象引入,同时也要引入获取天气数据的类,同时通过线程池来获取天气情况。
package test.dmdfchina.com.weathermvptest.presenter;
import com.thinkpage.lib.api.TPWeatherNow;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import test.dmdfchina.com.weathermvptest.model.BeanUtils;
import test.dmdfchina.com.weathermvptest.model.WeatManagerUtil;
/**
* Created by mkt on 2018/1/16.
*/
public class WeatherPresenter implements WeatherContract.IweatherPresenter {
private WeatherContract.IWeatherView weatherView;
private WeatManagerUtil weatManagerUtil = WeatManagerUtil.instance;//在其中定义了获取天气的方法
private ExecutorService executor = Executors.newFixedThreadPool(5);
@Override
public void initView(WeatherContract.IWeatherView view) {
this.weatherView = view;
weatherView.initView();
}
@Override
public void getWeather(final String cityName) {
executor.execute(new Runnable() {
@Override
public void run() {
weatManagerUtil.getWeatherState(cityName, new WeatManagerUtil.WeatherListener() {
@Override
public void onSucess(TPWeatherNow tpWeatherNow) {
weatherView.showWeatherState(BeanUtils.creatorBean(tpWeatherNow));
}
@Override
public void onFailed(String error) {
weatherView.onError(error);
}
});
}
});
}
@Override
public void onStart() {
}
@Override
public void onResume() {
}
@Override
public void onPause() {
}
@Override
public void onStop() {
}
@Override
public void onDestroy() {
}
}
通过以上的代码,你就会发现,presenter和View是怎么关联的,怎么处理逻辑业务的,同时你也能理解IView和IPresenter.java为什么要这么设计,还有更棒的,我觉得老师的这个架构写的很好 ,自己也学学,歇一歇,一会在继续对Activity的封装和使用吧。
嘿,回来了,继续吧,写好Model ,View和Presenter之后,就开始Activity了,但是大家发现我还有一个工具类,BeanUtils.java,这个工具类的作用就是将请求下来的天气数据设置给我们定义的model类,它采用的类似builder的设计模式。
package test.dmdfchina.com.weathermvptest.model;
import com.thinkpage.lib.api.TPWeatherNow;
/**
* Created by mkt on 2018/1/18.
*/
public class BeanUtils {
public static NowWeather creatorBean(TPWeatherNow tpWeatherNow){
NowWeather nowWeather=new NowWeather();
nowWeather.setText(tpWeatherNow.text);
nowWeather.setTemperature(tpWeatherNow.temperature);
nowWeather.setWindcale(tpWeatherNow.windScale);
nowWeather.setLastUpdateDate(tpWeatherNow.lastUpdateDate);
return nowWeather;
}
}
好了,这个工具类就到这里,下面看activity的写法吧,为了尽可能让界面一目了然,对activity也进行了封装了,创建BaseActivity.java为一个抽象类,其中封装了加载布局的方法,初始化Presenter的方法,事件处理方法,对处理完获取intent值的方法等,然后在OnCreate()方法调用这些方法即可。
package test.dmdfchina.com.weathermvptest.view;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.HashSet;
import java.util.Set;
import test.dmdfchina.com.weathermvptest.R;
import test.dmdfchina.com.weathermvptest.presenter.IPresenter;
public abstract class BaseActivity extends AppCompatActivity {
//一个Activity可能有多个Presenter
private Set<IPresenter> mAllPresenter = new HashSet<>(1);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayouId());
if (getIntent() != null) {
parseArgumentsFromIntent(getIntent());
}
addPresenter();
initPresenter();
initEvent();
}
/*定义加载布局的方法*/
public abstract int getLayouId();
//获取presenter的方法
public abstract IPresenter[] getPresenters();
//初始化presenter
public abstract void initPresenter();
//事件处理
public abstract void initEvent();
//处理从intent中传递过来的数据
public abstract void parseArgumentsFromIntent(Intent arguIntent);
//将有用的presenter添加到set集合中
public void addPresenter() {
IPresenter[] presenters = getPresenters();
if (presenters != null && presenters.length > 0) {
for (IPresenter mpresenter : presenters) {
mAllPresenter.add(mpresenter);
}
}
}
@Override
protected void onStart() {
super.onStart();
for (IPresenter mpresenter : getPresenters()) {
mpresenter.onStart();
}
}
@Override
protected void onResume() {
super.onResume();
for (IPresenter mpresenter : getPresenters()) {
mpresenter.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
for (IPresenter mpresenter : getPresenters()) {
mpresenter.onPause();
}
}
@Override
protected void onStop() {
super.onStop();
for (IPresenter mpresenter : getPresenters()) {
mpresenter.onStop();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
for (IPresenter mPresenter : getPresenters()) {
mPresenter.onDestroy();
}
}
}
接着写MainActivity.java,让其继承BaseActivity,之后重写抽象方法,同时继承IWeatherView接口,重写抽象方法等
package test.dmdfchina.com.weathermvptest;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import test.dmdfchina.com.weathermvptest.model.NowWeather;
import test.dmdfchina.com.weathermvptest.presenter.IPresenter;
import test.dmdfchina.com.weathermvptest.presenter.WeatherContract;
import test.dmdfchina.com.weathermvptest.presenter.WeatherPresenter;
import test.dmdfchina.com.weathermvptest.view.BaseActivity;
public class MainActivity extends BaseActivity implements WeatherContract.IWeatherView {
private WeatherPresenter mPresenter = new WeatherPresenter();
private TextView tv_show;
private Button btn_now_weather;
@Override
public int getLayouId() {
return R.layout.activity_main;
}
@Override
public IPresenter[] getPresenters() {
return new IPresenter[]{mPresenter};
}
@Override
public void initPresenter() {
mPresenter.initView(this);
}
@Override
public void initEvent() {
btn_now_weather.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "此处被点击", Toast.LENGTH_SHORT).show();
mPresenter.getWeather("beijing");
}
});
}
@Override
public void parseArgumentsFromIntent(Intent arguIntent) {
}
/*从IweathView实现的方法*/
@Override
public void initView() {
tv_show = (TextView) findViewById(R.id.tv_show);
btn_now_weather = (Button) findViewById(R.id.btn_now_weather);
}
@Override
public void showWeatherState(NowWeather nowWeather) {
tv_show.setText(nowWeather.getText());
}
@Override
public void onError(String errorMsg) {
tv_show.setText(errorMsg);
}
}
这时候你发现你的界面非常赶紧整洁,所有的逻辑业务全部封装在View和Presenter来处理,觉的这个模式写的很好,自己来加深加深印象,如果需要,可以读一读哦!