搭建自己的MVP框架
来源:互联网 发布:marry u软件下载 编辑:程序博客网 时间:2024/05/21 11:36
最近公司做的项目用到了MVP
,期间查了很多资料,也看了github
上别人搭的MVP
框架,基本用到dagger2
,也有的用到了别的技术,各种门类的都用,通过对比,选出了比较简易的搭建框架,用到的主要技术就是Retrofit2+RxJava2
,期间也学了不少RxJava
和Retrofit
的高级用法,比如服务器返回的Response
,token
时效性,失败重试机制,compose
的用法,感觉Rxjava
和Retrofit
还是很强大的。由于有的涉及到业务代码,就不方便贴出。在此记录下我们自己的框架搭建教程,方便以后回顾使用。
1.)项目net目录结构
我将项目公用的代码抽出为一个net
的module
,可以方便以后重复使用。项目的目录包名
app 存放的是一些全局变量,比如我们使用
retrofit
的base_url
mvp.base mvp的抽象提出到base中,方便不同
activity
和fragment
使用recyclerview 列表抽象封装,仿照
BRVAH
的封装retrofit_encapsulation
retrofit
的封装rx_encapsulation
rxjava
的封装type 泛型的实例化
接下来一一介绍这几个包名下的封装
2.) app
这个是仿照慕课网
,这门课的部分封装,其实与mvp
的封装没多大关系,但是这种封装可以统一管理多个全局变量的问题,当公司有多条业务线时,我们可以统一存储。
主要有三个类,AppConstant
, ConfigKeys
,Configurator
ConfigKeys
public enum ConfigKeys { API_HOST, APPLICATION_CONTEXT, CONFIG_READY, HANDLER,}
存放的是全局变量的引用,枚举方便引用。
ConfigKeys
public class Configurator { private static final HashMap<Object, Object> ANT_CONFIGS = new HashMap<>(); private static final Handler HANDLER = new Handler(); public Configurator() { ANT_CONFIGS.put(ConfigKeys.CONFIG_READY, false); } public static Configurator getInstance() { return Holder.INSTANCE; } private static class Holder { private static final Configurator INSTANCE = new Configurator(); } public final Configurator withApiHost(String apiHost) { ANT_CONFIGS.put(ConfigKeys.API_HOST, apiHost); return this; } final Configurator withApplicationContext(Context context) { ANT_CONFIGS.put(ConfigKeys.APPLICATION_CONTEXT, context.getApplicationContext()); return this; } private void checkConfiguration() { final boolean isReady = (boolean) ANT_CONFIGS.get(ConfigKeys.CONFIG_READY); if (!isReady) { throw new RuntimeException("Configuration is not ready,call configure"); } } /** * 配置完成 */ public final void configure() { ANT_CONFIGS.put(ConfigKeys.CONFIG_READY, true); } @SuppressWarnings("unused") final <T> T getConfiguration(Object key) { checkConfiguration(); final Object value = ANT_CONFIGS.get(key); if (value == null) { throw new NullPointerException(key.toString() + " IS NULL"); } return (T) ANT_CONFIGS.get(key); }}
用Hashmap
来作为容器,存放全局变量,由于要存放的类型不是固定的类型,使用了Object
来作为值得存储类型。
AppConstant
public class AppConstant { public static Configurator init(Context context) { Configurator.getInstance() .withApplicationContext(context); return Configurator.getInstance(); } public static Configurator getConfigurator() { return Configurator.getInstance(); } @SuppressWarnings("unused") public static <T> T getConfiguration(Object key) { return getConfigurator().getConfiguration(key); } public static Context getApplicationContext() { return getConfigurator().getConfiguration(ConfigKeys.APPLICATION_CONTEXT); } public static String getApiHost() { return getConfigurator().getConfiguration(ConfigKeys.API_HOST); }
我们每次要去获取值时候,直接通过AppConstant
来获取,比如获取存放的BaseUrl
,可以这样调用 AppConstant.getApiHost()
,每次获取只需要从AppConstant
获取
既然讲了获取全局变量的值当然要讲怎么存值。我们在使用这个包下面的东西时只需要这样使用
public class App extends Application{ String HOST = "http://news-at.zhihu.com/api/4/"; //自己公司的域名地址 @Override public void onCreate() { super.onCreate(); AppConstant.init(this) .withApiHost(HOST) .configure(); }}
在Application中做统一存储
3.) mvp.base
这个包下面是所有mvp
抽象的封装,所以东西还是挺多的。
主要有 BaseView
, BasePresenter
, BaseMVPActivity
, BaseModel
, BaseActivity
几个类,
BaseView
public interface BaseView { Context getContext(); void dealMsgError(String msg);}
所有view
接口的公用回调,这里如果不做处理,那么其他地方都要写,所以这里写,其他接口只需要继承这个接口就行了。
BaseModel
这个接口是一个空实现,只是为了抽象解耦的作用。
BasePresenter
public abstract class BasePresenter<V extends BaseView, M extends BaseModel> { protected V mView; protected M mModel; protected RxManager rxManager = new RxManager(); public void attachVM(V view, M model) { mView = view; mModel = model; } public void detachVM(){ rxManager.clear(); mView = null; mModel = null; }}
这个抽象类里面用到了两个泛型,是为了规范其实现类,同时这个类的实现是给Activity和Fragment实现和attach。同时这个类里面还用到了RxManager
,主要就是对CompositeDisposable
的包装,管理RxJava的生命周期,当页面结束时,自动取消RxJava的事件传递。
BaseMVPActivity
public abstract class BaseMVPActivity<P extends BasePresenter, M extends BaseModel> extends BaseActivity implements BaseView{ protected P mPresenter; protected M mModel; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { mPresenter = TUtil.getT(this, 0); mModel = TUtil.getT(this, 1); mPresenter.attachVM(this, mModel); super.onCreate(savedInstanceState); } @Override protected void onDestroy() { super.onDestroy(); if(mPresenter != null){ mPresenter.detachVM(); } } @Override public Context getContext() { return mContext; } @Override public void dealMsgError(String msg) { }}
这个类是对Activity中使用mvp的封装,我们如果使用只需要继承这个抽象的acitivity
就行了,同时指定需要的泛型具体实现,在BaseMVPActivity
中自动实例化泛型的参数。同时在抽象类中实现BaseView,可以避免在具体的activity中的空实现问题。
BaseActivity
就是不使用mvp的抽象,如果我们页面没有使用网络请求,可以不必实现BaseMVPActivity
。
4.) recyclerview
这个包路径是对recyclerview的封装,这个只是纯粹为了简化recyclerview的使用,与mvp无关,就不多说了,代码后面贴出,直接看代码。
5) retrofit_encapsulation
这个是对网络请求的抽象,我第一次封装时,没有考虑到多个BaseUrl的问题,Retrofit的创建都写死了,后来看了这门课Retrofit 从入门封装到源码解析,参照他的教程重新改了一遍。这个包下主要有两个类。分别是RetrofitManager
,RetrofitNet
RetrofitManager
public class RetrofitManager { private static Context mContext; private OkHttpClient mOkHttpClient; private static class InnerHolder { private static RetrofitManager INSTACE = new RetrofitManager(); } /** * 需要context时候调用,可以在Application中调用 * @param context */ public static void init(Context context) { //防止内存泄露 mContext = context.getApplicationContext(); } public static RetrofitManager getInstance() { return InnerHolder.INSTACE; } public Retrofit newRetrofit(String url) { // 拿到Retrofit实例 return new Retrofit.Builder() .baseUrl(url) //引入Gson解析库 ,就可以直接以实体的形式拿到返回值 .addConverterFactory(GsonConverterFactory.create()) //加入我们自定义的Gson解析库,就可以更友好的处理错误 //.addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) //将我们客制化的OkHttp实例传入 .client(mOkHttpClient) .build(); } private RetrofitManager() { //在构造方法里 最终是为了得到一个单例的OkhttpClient实例 OkHttpClient.Builder builder = new OkHttpClient.Builder(); //加入自己业务需要的拦截器 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { Log.i("OkHttp", message); } }); //缓存设置 //构建缓存位置 mOkHttpClient = builder.addInterceptor(loggingInterceptor).build(); }}
基本抄的那个视频的代码,主要就是实例化Retrofit
,同时我们可以在实例化Retrofit
的同时,加入Okhttp
拦截器,比如很常用的日志拦截器HttpLoggingInterceptor,由于Retrofit
默认不返回Json
,加入这个拦截器,可以极大提高我们调试技巧。同时也可以加入其他拦截器,可以根据业务自己判定。同时可以根据自己业务加入自定义的Gson解析。比如这样的结构
{ errorCode:1, msg:"成功", data:{ ..... }}
我们只需要data里面的内容,这时候我们就可以自定义Gson解析器,其实也就是改造GsonConverterFactory
的代码而已。
RetrofitNet
public class RetrofitNet { private static Retrofit mRetrofit; public static <T> T getService(Class<T> clazz) { return retrofit().create(clazz); } private static Retrofit retrofit() { if (mRetrofit == null) { mRetrofit = RetrofitManager.getInstance().newRetrofit(AppConstant.getApiHost()); } return mRetrofit; }}
通过这个去获取Retrofit
的实例,同时去构建Service
。
一般我们去获取Retrofit的原则是这样的
一个BaseUrl一个Retrofit实例
多个Retrofit共用一个OkHttp实例
6.) rx_encapsulation
对于RxJava的生命周期处理
RxManager
public class RxManager { private CompositeDisposable disposable = new CompositeDisposable(); public void add(Disposable d){ disposable.add(d); } public void clear(){ disposable.dispose(); disposable = null; }}
当生命周期结束,自动取消RxJava事件传递
7.) type
这个包下面的类是为了实例化Presenter和Model
public class TUtil { public static <T> T getT(Object o, int i) { try { return ((Class<T>) ((ParameterizedType) (o.getClass().getGenericSuperclass())).getActualTypeArguments()[i]).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassCastException e) { e.printStackTrace(); } return null; }}
利用反射去实例化Presenter和Model,来达到不用在Activity中手动实例化的目的。
8.) 使用
a. Contract规范View和Presenter,减少接口的创建
public interface HttpContract { interface View extends BaseView{ void getWelecomeDataSuccess(WelcomeBean welcomeBean); void getDailyList(DailyListBean respBean); } abstract class Presenter extends BasePresenter<View, HttpModel>{ public abstract void getWelecomData(String res); public abstract void getDailyList(); }}
b. Model
public class HttpModel implements BaseModel{ public Observable<DailyListBean> getDailyList(){ return RetrofitNet.getService(HttpService.class).getDailyList(); }}
统一调用HttpService的方法。
c.Presenter
public class HttpPresenter extends HttpContract.Presenter{ @Override public void getDailyList() { rxManager.add(mModel.getDailyList().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<DailyListBean>() { @Override public void accept(DailyListBean dailyListBean) throws Exception { mView.getDailyList(dailyListBean); } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception { mView.dealMsgError(throwable.getMessage()); } })); }}
d. Activity中指定泛型参数,统一实例化
public class MVPActivity extends BaseMVPActivity<HttpPresenter, HttpModel> implements HttpContract.View//使用 mPresenter.getDailyList();
基本使用也就这多了。
9. 结尾
其实还有好多没写出来,一是自己能力不够,二是对RxJava掌握还是不够好,以后会写点Retrofit的源码,加深下自己网络框架方面的学习。
源码地址
- 搭建自己的MVP框架
- 搭建属于自己的MVP+RXJAVA2+Retroft2框架
- Mvp+RxJava2+Retrofit2 搭建一个属于自己的开发框架
- Mvp+RxJava2+Retrofit2 搭建一个属于自己的开发框架
- 简易Mvp+RxJava2+Retrofit2 搭建一个属于自己的开发框架
- 搭建一个基本的MVP框架
- Retrofit+RXJava+MVP的框架搭建
- 搭建MVP模板框架
- MVP入门框架搭建
- 搭建自己的PHP框架
- 搭建自己的MVC框架
- RXjava+Retrofit+dagger2打造自己的MVP框架
- 自己整合的Android mvp+singlenet小框架
- 搭建MVP框架要点记录
- Android中的MVP框架搭建
- MVP架构实现的Github客户端(2-搭建项目框架)
- 从零开始搭建一个完善的MVP开发框架
- MVP模式开发之项目框架的搭建
- Mybatis入门简版(一)
- java第二篇
- 【备忘】最新大数据快速数据挖掘平台RapidMiner数据分析视频教程
- 实验八 文件读写
- 图像分割(一)轮廓提取
- 搭建自己的MVP框架
- ubuntu 配置samba
- JavaScript
- 我的第一篇
- Mybatis入门简版(二)
- 晶振不集成到IC内部,为什么?
- 5.1,从键盘任意输入一个实数,不使用计算绝对值函数编程计算并输出该实数的绝对值。
- 开发者们,2017年你们过得好吗?
- 企业级服务器应用、RAID、Cache和Buffer的区别、程序、进程、守护进程的区别