浅谈自己对mvp的理解,仅仅供自己理解mvp

最近公司的项目也不是太紧了,之前有用过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) {

        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来处理,觉的这个模式写的很好,自己来加深加深印象,如果需要,可以读一读哦!




发布了8 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/honey_angle_first/article/details/79093540