搭建自己的MVP框架

最近公司做的项目用到了MVP,期间查了很多资料,也看了github上别人搭的MVP框架,基本用到dagger2,也有的用到了别的技术,各种门类的都用,通过对比,选出了比较简易的搭建框架,用到的主要技术就是Retrofit2+RxJava2,期间也学了不少RxJavaRetrofit的高级用法,比如服务器返回的Responsetoken时效性,失败重试机制,compose的用法,感觉RxjavaRetrofit还是很强大的。由于有的涉及到业务代码,就不方便贴出。在此记录下我们自己的框架搭建教程,方便以后回顾使用。


1.)项目net目录结构

这里写图片描述

我将项目公用的代码抽出为一个netmodule,可以方便以后重复使用。项目的目录包名

  • app 存放的是一些全局变量,比如我们使用retrofitbase_url

  • mvp.base mvp的抽象提出到base中,方便不同activityfragment使用

  • 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;
    }
}

这个抽象类里面用到了两个泛型,是为了规范其实现类,同时这个类的实现是给ActivityFragment实现和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 从入门封装到源码解析,参照他的教程重新改了一遍。这个包下主要有两个类。分别是RetrofitManagerRetrofitNet

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的源码,加深下自己网络框架方面的学习。

源码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的 MVP 框架,包含 Okhttp+Retrofit 网络封装,Base 基类的抽取以及 APPLocation 的代码: 1. 首先创建一个 BaseView 接口,定义一些公共的 UI 操作方法: ```java public interface BaseView { void showLoading(); void hideLoading(); void showError(String error); } ``` 2. 接着创建一个 BasePresenter 类,定义一些公共的 Presenter 操作方法: ```java public class BasePresenter<V extends BaseView> { private WeakReference<V> mViewRef; public void attachView(V view) { mViewRef = new WeakReference<>(view); } public void detachView() { if (mViewRef != null) { mViewRef.clear(); mViewRef = null; } } public boolean isViewAttached() { return mViewRef != null && mViewRef.get() != null; } public V getView() { return mViewRef.get(); } public void checkViewAttached() { if (!isViewAttached()) throw new RuntimeException("Please call attachView() before requesting data to the Presenter"); } } ``` 3. 创建一个 BaseActivity 类,作为所有 Activity 的基类,包含一些公共的操作: ```java public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView { protected P mPresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); mPresenter = createPresenter(); if (mPresenter != null) { mPresenter.attachView(this); } initView(); } @Override protected void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.detachView(); } } protected abstract int getLayoutId(); protected abstract P createPresenter(); protected abstract void initView(); } ``` 4. 接着创建一个 BaseFragment 类,作为所有 Fragment 的基类,也包含一些公共的操作: ```java public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements BaseView { protected P mPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); if (mPresenter != null) { mPresenter.attachView(this); } } @Override public void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.detachView(); } } protected abstract P createPresenter(); } ``` 5. 创建一个 AppApplication 类,作为整个应用程序的入口,包含一些公共的配置信息和初始化操作: ```java public class AppApplication extends Application { private static AppApplication sInstance; @Override public void onCreate() { super.onCreate(); sInstance = this; // 初始化网络请求 RetrofitClient.getInstance().init(this); } public static AppApplication getInstance() { return sInstance; } } ``` 6. 创建一个 RetrofitClient 类,用于封装 Okhttp+Retrofit 网络请求: ```java public class RetrofitClient { private static final String TAG = "RetrofitClient"; private static final int DEFAULT_TIMEOUT = 30; private Retrofit mRetrofit = null; private OkHttpClient mOkHttpClient = null; private RetrofitClient() {} public static RetrofitClient getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { private static final RetrofitClient INSTANCE = new RetrofitClient(); } public void init(Context context) { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); mOkHttpClient = new OkHttpClient.Builder() .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .addInterceptor(loggingInterceptor) .addInterceptor(new TokenInterceptor()) .build(); mRetrofit = new Retrofit.Builder() .baseUrl(ApiService.BASE_URL) .client(mOkHttpClient) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } public ApiService getApiService() { return mRetrofit.create(ApiService.class); } } ``` 7. 创建一个 ApiService 接口,定义所有的网络请求接口: ```java public interface ApiService { String BASE_URL = "https://www.example.com/"; @POST("login") Observable<BaseResponse<User>> login(@Query("username") String username, @Query("password") String password); } ``` 8. 最后,我们可以创建一个 LoginPresenter 类,来处理登录相关的业务逻辑: ```java public class LoginPresenter extends BasePresenter<LoginContract.View> implements LoginContract.Presenter { private ApiService mApiService; public LoginPresenter() { mApiService = RetrofitClient.getInstance().getApiService(); } @Override public void login(String username, String password) { checkViewAttached(); getView().showLoading(); mApiService.login(username, password) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<BaseResponse<User>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(BaseResponse<User> userBaseResponse) { getView().hideLoading(); if (userBaseResponse.getCode() == 0) { getView().loginSuccess(userBaseResponse.getData()); } else { getView().showError(userBaseResponse.getMsg()); } } @Override public void onError(Throwable e) { getView().hideLoading(); getView().showError(e.getMessage()); } @Override public void onComplete() { } }); } } ``` 以上就是一个简单的 MVP 框架的实现,您可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值