最近在学习开发模式中的MVP模式,看了鸿洋大神的一篇MVP浅学http://blog.youkuaiyun.com/lmj623565791/article/details/46596109【鸿洋大神的mvp介绍】,我自己也知道MVP开发模式简直好用到不行,完全能够知道自己错误是在哪里,逻辑还很清晰,看着以前写的代码简直痛苦的要死,自从学会了这个模式后感觉像是在编码界得到了新生一样--------爽
很久没有看到了这个博客这时看见已经有很多人阅读但是对于我这种不怎么说话的,和第一个词使用csdn的人看见我这种模式都是望而生畏吧,但是我坚信如果是很想学习的人会把我的代码一个一个粘贴复制的话,是一定能跑起来的。这里我从新结束一些mvp模式希望真正的对你起作用。
retrofit使用详细介绍:http://blog.youkuaiyun.com/lmj623565791/article/details/51304204鸿洋大神
RxJava使用详细介绍:http://www.jianshu.com/p/64aa976a46be和http://www.jianshu.com/u/c50b715ccaeb
为retrofit+RxJava添加下面的依赖(这里是RxJava1)
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
这里是RxJava2依赖
//retrofit compile 'com.squareup.retrofit2:retrofit:2.1.0' //Gson converter compile 'com.squareup.retrofit2:converter-gson:2.1.0' //RxJava2 Adapter compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' //okhttp compile 'com.squareup.okhttp3:okhttp:3.4.1' compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
mvp说真话懂得人不难,不懂的人第一次看见这种写法估计都是头大了这次我来一次极其简单方式来讲解希望能懂。
- View 对应于Activity,负责View的绘制以及与用户交互
- Model 依然是业务逻辑和实体模型
- Presenter 负责完成View于Model间的交互
在说直白点不就是在model中拿到下载的数据?怎么拿到呢?不就是在Persenter层创建Model的实例在调用Model方法获取数据。
获取数据之后不就是在调用View的接口把拿到的数据放入方法中(用到接口回调)...具体我们来看我自己写的一个极其简单例子
先看整体图
我们先来看Model层这里我是模拟从服务器拿到数据
getData()不就是一个从服务器拿到的数据吗?然后在Persenter层创建Model的实例调用getData()方法不就是拿到数据了吗?//modle就是为了实现从服务器拿到数据 public class Modle { private Modle mModle; public String getData(){ return "获取数据"; } }
再来看Persenter层
从上面的代码可以看出我是不是一开始就创建了两个字段分别为mModle和mView(这里的view就是为了实现那个类继承了他就传入那个对象进来)public class Persenter { private Modle mModle;// private View mView;// public Persenter(View view) { mView = view; mModle = new Modle();//在构造函数中直接初始化Model的实例 } public Persenter() { } public void getData(){ mView.getData(mModle.getData());//把数据方法接口View的getData()中 } }
在构造函数中直接初始化Model,写一个方法把从Model层获得数据放入View中,View中的getData()是不是有数据了(接口回调)。
在来View层(简单不行)就一个接口一个方法public interface View { void getData(String data); }
然后我们把那个Activity需要这个数据那么就把那个Activity继承View不就拿到了数据?
再来看Activity
然后在结合Retrofit+RxJava来使用public class MainActivity extends AppCompatActivity implements View { private TextView mTextView; private Persenter mPersenter;//创建Persentershili @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView= (TextView) findViewById(R.id.text); mPersenter=new Persenter(this);//创建Persenter实例 mPersenter.getData();//调用方法 } @Override public void getData(String data) {//这里的data就有数据我们直接把它setText中去就有数据了。简单粗暴 mTextView.setText(data); }
如果大家不懂retrofit和Rxjava请到上面去看怎么使用这里不过多解释了。
请看代码
我们只要把retrofit封装成到一个类中只管调用不就行了吗?
这里我们来看加上RxJava+Retrofit后的代码
现在看整体图
同理上面的图和最开始的时候的图没有多大的区别
1.我们先把Retrofit请求数据操作写在一个类中进行简单的封装看代码
API
Bean文件你们就自己根据这个接口去生成吧public interface API { @GET("ProductBrand") Observable<Bean>getData(); }
ConStanshttp://api.shiandianping.com/api/sourceAndroidDianPing/v1.0/ProductBrand
这些准备好我们就开始写Retrofit的数据请求操作public class Constans { public static final String URL_HEAD = "http://api.shiandianping.com"; /** * 请求来源 */ public static final String URL_SOURCE = "sourceAndroidDianPing"; /** * URL */ public static final String BASE_URL = URL_HEAD+"/api/" + URL_SOURCE + "/v1.0/"; }
public class Http { //retrofit的操作 public static Retrofit getRetrofit(){ OkHttpClient.Builder builder=new OkHttpClient.Builder(); builder.readTimeout(10, TimeUnit.SECONDS); builder.connectTimeout(9,TimeUnit.SECONDS); if (BuildConfig.DEBUG){ HttpLoggingInterceptor interceptor=new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); builder.addInterceptor(interceptor); } return new Retrofit.Builder() .baseUrl(Constans.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(builder.build()) .build(); } }
2.这些做完我们就来看model中做了哪些操作和上面第一例子有什么区别
public class IBaseModel<T extends BasePersenter> { public T presenter; public IBaseModel(T presenter) { this.presenter = presenter; } }
3.在onNext()不就是有了数据我们只要把数据放入presenter.getDataSuccess()不就是有了数据//modle就是为了实现从服务器拿到数据 public class Modle extends IBaseModel<Persenter>{ private Modle mModle; public Modle(Persenter presenter) { super(presenter); } public void getData(){ API api = Http.getRetrofit().create(API.class); api.getData()//RxJava方便体现出来了 .subscribeOn(Schedulers.newThread())//把ObServable的操作(网络请求)运行在子线程 .observeOn(AndroidSchedulers.mainThread())//把observer的操作(也就是给UI数据)运行在主线程 .subscribe(new Observer<Bean>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Bean value) { presenter.getDataSuccess(value);//拿到数据 } @Override public void onError(Throwable e) { presenter.getDataFailure(e.getMessage()); } @Override public void onComplete() { } }); } }
在来看Presenter
public class BasePersenter { }
4.在Activity中调用拿到数据public class Persenter extends BasePersenter{ private Modle mModle; private View mView; public Persenter(View view) { mView = view; mModle = new Modle(this); } public void getData(){ mModle.getData(); } public void getDataSuccess(Bean bean){ mView.getDataSuccess(bean);//是不是和上面的第一个例子很像?不错这里就是调用接口回调吧数据入View这接口的方法中 } public void getDataFailure(String s){ mView.getDataFailure(s); }
好的在这里RxJava+Retrofit就这结束了希望对你有所帮助好好看第一个例子来结合第二个例子你会有很多收获我觉得希望对你又说帮助public class MainActivity extends AppCompatActivity implements View { private TextView mTextView; private Persenter mPersenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView= (TextView) findViewById(R.id.text); mPersenter=new Persenter(this); mPersenter.getData(); } @Override public void getDataSuccess(Bean data) { mTextView.setText(data.getMssage()); } @Override public void getDataFailure(String s) { } }
下面这你们可以不看了这是我以前写的例子有些不完整了。
列表截图:
BaseActivity:
/**
定义一个Activity基类这里使用<T extends BasePresenterI,V>中T extends BasePresenterI主要是获取到Presenter类的实例,
V:获取JavaBean对象(如:传一个GankBean)继承BaseView<V>这里给的是泛型,在主函数中自己给定想要的什么数据类型的泛型*/
public abstract class BaseActivity<T extends BasePresenterI,V> extends AppCompatActivity implements BaseView<V> { public T mPresenter;//定义一个Presenter类 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId());//设置XML文件 if (mPresenter==null){//判断是否为空 mPresenter=getPresenter();获取presenter } initData(); initView(); } protected abstract int getLayoutId(); protected abstract void initData(); protected abstract void initView(); public T getPresenter() { return null; } @Override protected void onDestroy() { mPresenter.unSubcrible();//解除RxJava的订阅 super.onDestroy(); } }
BasePresenter:
/**这里的泛型是规定要那个在使用它
public class BasePresenter<T extends BaseView> implements BasePresenterI{ public T mView; public Context context; public CompositeSubscription mCompositeSubscription;//获取一个被订阅者的容器 //解除订阅 @Override public void unSubcrible() { if (mCompositeSubscription!=null){//判断容器是否为空 mCompositeSubscription.unsubscribe(); mView=null; context=null; } } //添加订阅者 public void addCompositeSubscription(Subscription s){ if (mCompositeSubscription==null){ this.mCompositeSubscription=new CompositeSubscription(); } mCompositeSubscription.add(s); } //判断是否有网络这里没有使用它。 @Override public boolean checkNetwork() { ConnectivityManager connectivityManager = (ConnectivityManager) MyAppliction.getContext().getSystemService(Context.CONNECTIVITY_SERVICE); if(connectivityManager!=null){ NetworkInfo info = connectivityManager.getActiveNetworkInfo(); if(info!=null&&info.isConnected()){ if (info.getState()==NetworkInfo.State.CONNECTED) return true; } } return false; } }
BasePresenterI
public interface BasePresenterI { void unSubcrible(); boolean checkNetwork(); }
BaseView:
//这里泛型主要是为了泛型的数据类型做准备 public interface BaseView<T> { public void getData( T datas); } 主函数MainActivity //这里的BaseActivity<GanksPresenter, GanksBean>就是看那个Presenter在使用然后获取当前presenter对象 public class MainActivity extends BaseActivity<GanksPresenter, GanksBean> implements ConstrctValues.Gansk { private TextView mTextView; @Override protected int getLayoutId() { return R.layout.activity_main; } //让其获取数据的函数运行在主线程 @Override protected void initData() { mPresenter.getSurroceData(); } @Override protected void initView() { mTextView= (TextView) findViewById(R.id.msg); } //就是去网络下载的数据应用于:接口回调获得数据 @Override public void getData(GanksBean datas) { if (datas!=null){ mTextView.setText(datas.toString()); } } //获得当前的presenter对象 @Override public GanksPresenter getPresenter() { return new GanksPresenter(this); } @Override protected void onDestroy() { mPresenter.unSubcrible(); super.onDestroy(); } } public interface ConstrctValues { //直接给BaseView是那个类型 public interface Gansk extends BaseView<GanksBean>{}; public interface Presenter{ void getSurroceData(); } } public class MyAppliction extends Application { public static MyAppliction myAppliction; @Override public void onCreate() { super.onCreate(); myAppliction=this; } public static Context getContext(){ return myAppliction.getApplicationContext(); } }
Http中
ConstantValues :定义apipublic class ConstantValues { /*public static boolean ISUPLOAD = false; public static final String packageName = "com.android.mvp"; public static final String MAIN_HTML = "http://www.shiandianping.com";*/ // 正式服务器 public static final String URL_HEAD = "http://api.shiandianping.com"; /** * 请求来源 */ public static final String URL_SOURCE = "sourceAndroidDianPing"; /** * URL */ public static final String BASE_URL = "/api/" + URL_SOURCE + "/v1.0/"; // public static final String PATH="api/sourceAndroidDianPing/v1.0/ProductBrand"; // http://api.shiandianping.com/api/sourceAndroidDianPing/v1.0/ProductBrand /** * 首页 * */ //首页轮播图 //public static final String Home_Banner=BASE_URL+"Banner"; //首页产品类别 // public static final String Home_ProductBrand=BASE_URL+"ProductBrand"; // public static final String Home_ProductBrand1=URL_HEAD+PATH; //首页社区 //public static final String HOME_Posts=BASE_URL+"posts/GetHeatPost"; //首页专题 //public static final String Home_SpecialTopic=BASE_URL+"SpecialTopic"; //专题详情 // public static final String SpecialInfo=BASE_URL+"SpecialTopic";
RxJava+retrofit的配合使用
GanksAPI :定义方法获取数据
public interface GanksAPI { @GET(ConstantValues.BASE_URL+"{ProductBrand}") Observable<GanksBean> observable(@Path("ProductBrand")String ProductBrand); } //使用单例模式获取Http的实例 public class Http { private static Http http=null; private Retrofit mRetrofit; private GanksAPI ganksAPI; public static Http getInstance(){ if (http==null){ http=new Http(); return http; } return null; } Http(){ //retrofit的使用 OkHttpClient client=new OkHttpClient(); mRetrofit=new Retrofit.Builder() .baseUrl(ConstantValues.URL_HEAD) .client(client) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); this.ganksAPI=mRetrofit.create(GanksAPI.class); } //返回一个Obserable(被观察者) public GanksAPI getGanksAPI(){ return ganksAPI; } }
model中主要是从网络获取数据下载这里是使用retrofit进行数据下载,RxJava把数据回抛到主线程
public class GankModel { public Observable<GanksBean> getObservable(){ return Http.getInstance().getGanksAPI().observable("ProductBrand").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); } } presenter中: public interface ConstrctValues { public interface Gansk extends BaseView<GanksBean>{}; public interface Presenter{ void getSurroceData(); } } //这里泛型主要是规定数据类型的形式 public class GanksPresenter extends BasePresenter<ConstrctValues.Gansk> implements ConstrctValues.Presenter { //获取一个BaseView的对象 private ConstrctValues.Gansk ganksBean; //获取一个model对象 private GankModel gankModel; public GanksPresenter(ConstrctValues.Gansk ganksBean) { this.ganksBean = ganksBean; this.gankModel=new GankModel(); //这里必须把BasePresenter的mView赋值否则回报空指针异常,被坑了好几次这里 注意了 mView=this.ganksBean; } @Override public void getSurroceData() { //将Observable添加容器中 addCompositeSubscription(gankModel.getObservable().subscribe(new Action1<GanksBean>() { @Override public void call(GanksBean ganksBean) { //将数据放入接口的方法中在主MainActivity中就有获取的方法 mView.getData(ganksBean); Log.e("tag","sssss"+ganksBean.toString()); } })); } }