Android

MVP抽取

2020-06-09  本文已影响0人  夜沐下的星雨

描述:

当我们的逻辑功能越来越多,每个功能点都要写一套MVP,是一件很繁琐的事情。因此我们要对MVP的进行封装和抽取。

View 视图层 有activity Fragment view 来代表,UI层面的有时候也会有一些共性问题,比如都是展示成功数据,展示失败数据,展示加载中,加载异常等等。所以针对View 抽取一个接口baseView。

Presenter 中间层 是View Model之间交互的桥梁。Presenter是个中间对象,所以他的抽取只是对View Model的抽取。但是Model没有什么共性特点,业务的处理不一样。所以就剩下View的特点,咱们在初始化P的会传入view的引用,这个view 有可能是Activity或者fragment,所以就要考虑生命周期导致的内存泄漏问题,要及时清除对象之间的依赖关系。

Model 业务逻辑 模型层 负责耗时任务处理,单纯的处理数据,比较独立,这里的写法把M给弱化了。你也可以理解为省略了。这样反而省去了M层和Callback的类,简化之间的逻辑。从上述思路也可以看出,MVP是一种思想,不是固定的代码模版。

一、为什么要抽取?

每一个页面都用到同样的内容,每次都写同样的代码,浪费;

规定代码的编写规范;

多人开发维护变得简单。

二、抽取那些内容

通用的操作

三、设计模式

模板设计模式(让子类的工作模式都按照父类的执行)

单例设计模式

四、具体抽取

MVP抽取概述图:

image

网络抽取
①创建网络管理类,使用双检索单例设计模式获取对象

public class HttpUtil {
    private static HttpUtil httpUtil;

    public static HttpUtil getHttpUtil() {
        if (httpUtil == null) {
            synchronized (HttpUtil.class) {
                if (httpUtil == null) {
                    httpUtil = new HttpUtil();
                }
            }
        }
        return httpUtil;
    }
}

②在网络管理器的构造中获取Retrofit的builder对象

public class HttpUtil {
    private final Retrofit.Builder builder;
    private HttpUtil() {
        builder = new Retrofit.Builder()
                .client(getHttpClient())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create());
    }
}

③使用泛型获取ApiService对象
//一个返回T类型的方法,T的类型的泛型

public class HttpUtil {
    public <T> T getService(String baseurl, Class<T> mClass) {
        return builder.baseUrl(baseurl).build().create(mClass);
    }
}

④自定义OKHTTPClient,设置超时、请求头、拦截器等

public class HttpUtil {
     private OkHttpClient getHttpClient() {
        //设置本地缓存文件
        File file = new File(Constants.PATH_CACHE);
        //设置缓存
        Cache cache = new Cache(file, 1024 * 1024 * 50);

        //设置日志拦截器
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG) {
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        } else {
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
        }

        return new OkHttpClient.Builder()
                .cache(cache)
                .addInterceptor(httpLoggingInterceptor)
                .addNetworkInterceptor(new MyCacheIntercepter())
                .addInterceptor(new MyCacheIntercepter())
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
    }

    //网络拦截器
    public class MyCacheIntercepter implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            if (!isNetworkAvailable(GeekApplication.getApplication())) {
                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();

            }

            Response originalResponse = chain.proceed(request);

            if (isNetworkAvailable(GeekApplication.getApplication())) {
                int maxAge = 0;
                return originalResponse.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public ,max-age=" + maxAge)
                        .build();
            } else {
                int maxStale = 15 * 60;
                return originalResponse.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                        .build();
            }
        }
    }

    public static boolean isNetworkAvailable(Context context) {
        if (context != null) {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = cm.getActiveNetworkInfo();
            if (info != null) {
                return info.isAvailable();
            }
        }
        return false;
    }
}

⑤抽取线程切换

public class RxUtil {
    /**
     * <T ,T > T转换前的对象类型, T 转换后的对象类型
     *
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> rxObservableTransformer() {
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io());
            }
        };
    }
}

⑥观察者抽取

public abstract class BaseObserver<T> implements Observer<T> {
    @Override
    public void onSubscribe(Disposable d) {
        Log.e("TAG", "订阅成功");
    }

    @Override
    public void onError(Throwable e) {
        onFail("onError:" + e.getMessage());
    }

    @Override
    public void onComplete() {
        Log.e("TAG", "请求完成");
    }

    @Override
    public void onNext(T value) {
        onSuccess(value);
    }

    public abstract void onFail(String error);

    protected abstract void onSuccess(T t);
}

⑦使用

HttpManager.getHttpManager().getApiService(ApiService.baseLoginUrl, ApiService.class)
                .login(name, pwd)
                .compose(RxUtil.<LoginBean>rxTransform())
                .subscribe(new BaseObserver<LoginBean>() {
                    @Override
                    public void onSucess(LoginBean loginBean) {
                        if (loginBean.getErrorCode() == 0) {
                            callBack.onSucess(loginBean);
                        } else {
                            callBack.onFail(loginBean.getErrorMsg());
                        }
                    }

                    @Override
                    public void onFail(String error) {
                        callBack.onFail(error);
                    }
                });

BaseActivity抽取

public abstract class BaseActivity<P extends BasePresenter, V extends BaseView> extends AppCompatActivity {
    protected P mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        ButterKnife.bind(this);
        mPresenter = initPresenter();
        if (mPresenter != null) {
            mPresenter.setmView(initMvpView());
        }
        initView();//有些子类需要,有些不需要
        initData();//有些子类需要,有些不需要,仅仅用普通方法即可
        initListener();
    }

    protected abstract void initListener();

    protected abstract void initData();

    protected abstract void initView();

    protected abstract V initMvpView();

    protected abstract P initPresenter();

    protected abstract int getLayoutId();

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenter.onDestory();
        mPresenter = null;
    }
}

BaseModel抽取

public class BaseModel {
    public CompositeDisposable mCompositeDisposable;

    public void onDestory() {
        //切断所有的Disposable对象
        if (mCompositeDisposable != null){
            mCompositeDisposable.clear();
        }
    }

    public void addDisposable(Disposable d){
        if (mCompositeDisposable == null){
            mCompositeDisposable = new CompositeDisposable();
        }
        mCompositeDisposable.add(d);
    }
}

BaseView 抽取

public interface BaseView<T> {
    void onSucess(T t);

    void onFail(String error);
}
BasePresenter抽取
public abstract class BasePresenter<V extends BaseView> {
    protected V mView;
    private ArrayList<BaseModel> mModels = new ArrayList<>();

    public BasePresenter() {
        initMdel();
    }

    protected abstract void initMdel();

    public void setmView(V mView) {
        this.mView = mView;
    }

    public void onDestory() {
        //打断P层和V层的联系,
        mView = null;
        //掐断网络请求
        if (mModels.size() > 0) {
            for (BaseModel model : mModels) {
                model.onDestory();
            }
            mModels.clear();
        }
    }

    public void addModel(BaseModel model) {
        mModels.add(model);
    }
}

callback抽取

public interface BaseCallBack<T> {
    void onSuccess(T t);
    void onFail(String error);
}

MVP抽取案例使用(登录)

M层

public class LoginModel extends BaseModel {
    public void login(String name, String password, BaseCallBack<String, String> callBack) {
        if (true) {
            callBack.onSuccess("登录成功");
        } else {
            callBack.onFail("登录失败");
        }
    }
}

P层

public class LoginPresenter extends BasePresenter<LoginView, LoginModel> implements BaseCallBack<String, String> {
    public void login(String name, String pwd) {
        if (model != null) {
            model .login(name, pwd, this);
        }
    }

    @Override
    public void onSuccess(String s) {
        if (view != null) {
            view .onSuccess(s);
        }
    }

    @Override
    public void onFail(String s) {
        if (view  != null) {
            view .onFail(s);
        }
    }
}

V层

public class MainActivity extends BaseActivity<LoginPresenter, LoginView, LoginModel> implements LoginView {

    @BindView(R.id.btn_login)
    Button btnLogin;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected LoginView initMvpView() {
        return this;
    }

    @Override
    protected LoginModel initMvpModel() {
        return new LoginModel();
    }

    @Override
    protected LoginPresenter initPresnter() {
        return new LoginPresenter();
    }

    @Override
    public void onSuccess(String s) {
        Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onFail(String s) {
        Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
    }

    @OnClick({R.id.btn_login})
    public void onViewClicked(View view) {
                baseP.login("", "");   
    }

MVP与普通的分离(不需要mvp的页面)

不需要MVP

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        ButterKnife.bind(this);
        initMvp();
        initView();//有些子类需要,有些不需要
        initData();//有些子类需要,有些不需要,仅仅用普通方法即可
        initListener();
    }

   private void initMvp() {}

    protected abstract int getLayoutId();
    
    private void initListener() {}

    private void initData() {}

    protected void initView() {}
}

需要mvp

public abstract class BaseMVPActivity<P extends BasePresenter, V extends BaseView, M extends BaseModel> extends BaseActivity {
    protected P presenter;

    @Override
    public void initMvp() {
        super.initMvp();

        presenter = initPresnter();
        if (presenter != null) {
            presenter.addView(initMvpView());
            presenter.addModel(initMvpModel());
        }
    }

    protected abstract V initMvpView();

    protected abstract M initMvpModel();

    protected abstract P initPresnter();
}

Fragment抽取

没有MVP抽取基类

public abstract class BaseFragment extends Fragment {

    private Unbinder unbinder;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(getLayoutId(), container, false);
        unbinder = ButterKnife.bind(this, view);
        initMvp();
        initView();
        initData();
        initListener();
        return view;
    }

    protected void initMvp() {

    }

    protected void initListener() {

    }

    protected void initData() {

    }

    protected void initView() {

    }

    protected abstract int getLayoutId();

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }
}

有MVP抽取

public abstract class BaseMvpFragment<P extends BasePresenter, V extends BaseView, M extends BaseModel> extends BaseFragment {
    protected P presenter;

    @Override
    protected void initMvp() {
        super.initMvp();
        presenter = initPresnter();
        if (presenter != null) {
            presenter.addView(initMvpView());
            presenter.addModel(initMvpModel());
        }
    }

    protected abstract V initMvpView();

    protected abstract M initMvpModel();

    protected abstract P initPresnter();
}

应用崩溃问题解决:

背景:在发动网络请求的时候,退出当前activity
冲突:此时如果回到主线程更新UI,APP会崩溃
解决:当activity退出时,调用DisPosable.dispose()切断观察者和被观察者的连接,使得观察者无法收到事件&响应事件;当出现多个disposable时,采用Rxjava内置容器CompositeDisposable进行统一管理

CompositeDisposable compositeDisposable = new CompositeDisposable();
//添加disposable到CompositeDisposable容器
compositeDisposable .add();
//清空CompositeDisposable容器,在父类的baseModel中调用
compositeDisposable .clear();

在BaseModel中:

public abstract class BaseModel {
    
    //用于统一切断观察者与被观察者关系
    CompositeDisposable compositeDisposable = new CompositeDisposable();

    //切断,P层调用
    public void destroy() {
        compositeDisposable.clear();
    }
}

在basePresenter中

public class BasePresenter<V extends BaseView, M extends BaseModel> {

    //创建一个集合,用于存放model
    protected ArrayList<BaseModel> list = new ArrayList<BaseModel>();

    protected V view;
    protected M model;

    public void addView(V v) {
        this.view = v;
    }

    public void addModel(M m) {
        this.model = m;
        //添加model
        list.add(m);
    }

    public void destroy() {
        //如果view不为空,页面关闭,强制置空,否则内存泄漏
        if (view != null) {
            view = null;
        }

        //如果页面关闭,切断网络请求的观察者与被观察者的关系
        if (list.size() > 0) {
            for (BaseModel baseModel : list) {
                baseModel.destroy();
            }
        }

        //如果model不为空,置空
        if (model != null) {
            model = null;
        }
    }
}

在BaseMVPActivity中:

  /**
     * 页面关闭时
     * 切断连接
     * 内存回收
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (presenter != null) {
            presenter.destroy();
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读