MVP抽取

作者: HOLLE_karry | 来源:发表于2020-05-31 22:52 被阅读0次

一、抽取原因

每一个页面都用到同样的内容,每次都写同样的代码,浪费;
规定代码的编写规范;
多人开发维护变得简单。

二、设计模式

模板设计模式
单例模式

三、代码

1.相同的部分

⑴抽取V层(吐司)

public interface BaseView {
    void showToast(String string);
}

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

//单列模式  懒汉式
public class BaseModel {
    //Rxjava内置容器CompositeDisposable
    private CompositeDisposable compositeDisposable = null;
    //所有的Disposable对象,都需要保存在CompositeDisposable中
    //Disposable
    //1.解除订阅关系
    //2.如果在进行网络请求,还可以取消网络请求
    public void addDisposable(Disposable disposable) {
        if (compositeDisposable == null) {
            compositeDisposable = new CompositeDisposable();
        }
    }
    //compositeDisposable.clear();
    //1.调用容器中Disposable的所有对象dispose();
    //2.会将容器清空
    public void destory() {
        compositeDisposable.clear();
    }
}

⑶抽取P层

//P层,view和model之间的桥梁
public abstract class BasePresenter<T extends BaseView> {

    public T mView;//每一个presenter要有一个view,view的类别必须是BaseView的后代,用泛型来表示
    //创建model集合
    public ArrayList<BaseModel> models = new ArrayList<>();
    //要先给view赋值(也就是先有布局),再给model赋值(再请求数据),现在还没有绑定view,要先写抽象方法
    public BasePresenter() {
        initModel();
    }

    protected abstract void initModel();//子类复写,用来初始化M层对象的
    //绑定view
    public void bindView(T view) {
        mView = view;
    }
    //添加model
    public void addModel(BaseModel baseModel) {
        models.add(baseModel);
    }
    //当页面销毁时走这个方法
    public void destory() {
        mView = null;//页面销毁的条件
        for (int i = 0; i < models.size(); i++) {
            BaseModel baseModel = models.get(i);//获取model的请求
            baseModel.destory();//将页面销毁
        }
    }

    public abstract void initData();
}

⑷抽取Activity层

public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity implements BaseView {
    public T mPresenter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayout());
        ButterKnife.bind(this);//加载布局
        initPresenter();//创建presenter
        if (mPresenter != null) {
            mPresenter.bindView(this);
        }
        initView();//设置布局
        initData();//网络请求
    }

    protected abstract void initPresenter();

    protected abstract void initView();

    protected abstract void initData();

    protected abstract int getLayout();
}

⑸callback抽取

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

⑹封装网络框架

1.使用起来更简洁,效率更高
2.日志打印,缓存数据,公共参数(请求头:token,os:Android,IOS)
3.三方框架:Rxjava+Retrofit+OkHttpClient

addDisposable(HttpUtil.getInstance()
                .getApiService()
                .getData()
                .compose(RxUtils.<MainBean>rxSchedulerHelper())
                .subscribeWith(new BaseSubscriber<MainBean>() {
                    @Override
                    public void onNext(MainBean mainBean) {
                        back.onSuccess((ArrayList<MainBean.DataBean.DatasBean>) mainBean.getData().getDatas());
                    }
                }));

2.其他的部分

⑴V层

public interface MainView extends BaseView {
    //MainView自己的方法,加载数据时调用
    void setData(ArrayList<MainBean.DataBean.DatasBean> datasBeans);
}

⑵M层

public class MainModel extends BaseModel {//网络请求
    public void initData(final MainCallBack<ArrayList<MainBean.DataBean.DatasBean>> arrayListMainCallBack) {
        new Retrofit.Builder()
                .baseUrl(ApiService.url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
                .create(ApiService.class)
                .getData()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MainBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(MainBean mainBean) {
                        if (mainBean != null) {
                            arrayListMainCallBack.onSuccess((ArrayList<MainBean.DataBean.DatasBean>) mainBean.getData().getDatas());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        arrayListMainCallBack.onFail(e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }
}

⑶P层

public class MainPresenter extends BasePresenter <MainView>{

    private MainModel mainModel;

    @Override
    protected void initModel() {//MainPresenter是子类,复写BasePresenter中的initModel方法,来添加model
        mainModel = new MainModel();
        models.add(mainModel);
    }
    //相当于实现callback,重写callback中的方法
    @Override
    public void initData() {
        //在M层中创建initData这个方法
        mainModel.initData(new MainCallBack<ArrayList<MainBean.DataBean.DatasBean>>() {
            @Override
            public void onSuccess(ArrayList<MainBean.DataBean.DatasBean> datasBeans) {
                mView.setData(datasBeans);
            }

            @Override
            public void onFail(String string) {
                mView.showToast(string);
            }
        });
    }

}

⑷Activity层

public class MainActivity extends BaseActivity<MainPresenter> implements MainView {

    @BindView(R.id.rv)
    RecyclerView rv;
    private ArrayList<MainBean.DataBean.DatasBean> list;
    private MainAdapter adapter;
    //调用Presenter的对象
    @Override
    protected void initPresenter() {
        mPresenter = new MainPresenter();
    }
    //设置布局
    @Override
    protected void initView() {
        rv.setLayoutManager(new LinearLayoutManager(this));
        rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        list = new ArrayList<>();
        adapter = new MainAdapter(this, list);
        rv.setAdapter(adapter);
    }
    //网络请求数据
    @Override
    protected void initData() {
        mPresenter.initData();
    }
    //找控件
    @Override
    protected int getLayout() {
        return R.layout.activity_main;
    }
    //失败的方法,吐司
    @Override
    public void showToast(String string) {
        Toast.makeText(this, string, Toast.LENGTH_SHORT).show();
    }

    //成功的方法,将数据添加进集合中并刷新适配器
    @Override
    public void setData(ArrayList<MainBean.DataBean.DatasBean> datasBeans) {
        list.addAll(datasBeans);
        adapter.notifyDataSetChanged();
    }
}

3.工具类

public class HttpUtil {
    //rxjava+retrofit+ok
    //单例
    //数据缓存,日志,请求头(开发一般是固定的,token...)
    //token,身份令牌

    private Retrofit.Builder mRetrofitBuilder;

    private HttpUtil() {
        //1.获取一个OkHttpClient
        OkHttpClient mOkHttpClient = getOkHttpClient();
        //2.获取到一个Retrofit.Builder
        getRetrofit(mOkHttpClient);
    }
    //在网络管理器的构造中获取Retrofit的builder对象
    private void getRetrofit(OkHttpClient okHttpClient) {
        mRetrofitBuilder = new Retrofit.Builder()
                .client(okHttpClient)//使用自定义的更强大的ok代替原来的弱鸡ok
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create());
    }

    //volatile
    private static volatile HttpUtil instance;

    //Double checked lock
    //创建网络管理类,使用双检索单例设计模式获取对象
    public static HttpUtil getInstance() {
        if (instance == null) {
            synchronized (HttpUtil.class) {
                if (instance == null) {
                    instance = new HttpUtil();
                }
            }
        }
        return instance;
    }

    /**
     * 固定模板
     * 创建带缓存的OkhttpClient
     * 1.添加了缓存
     * 2.添加了日志拦截器
     */
    //自定义OKHTTPClient,设置超时、请求头、拦截器等
    private OkHttpClient getOkHttpClient() {
        //设置本地缓存文件
        File cacheFile = new File(Constants.PATH_CACHE);
        //设置缓存文件大小
        //1 M = 1024Kb = 1024 * 1024 byte
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100);
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .cache(cache)//缓存
                .addInterceptor(new MyCacheinterceptor())
                .addNetworkInterceptor(new MyCacheinterceptor())
                //添加了请求头拦截器之后,所有使用网络框架的网络请求都会添加拦截器中的请求头
                //不需要请求头的也加了请求头,是不影响请求
                //.addInterceptor(new HeadersInterceptor())
                //设置写入时间
                .writeTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                //设置错误重连
                .retryOnConnectionFailure(true);
        //如果是debug状态(码农调试应用),添加日志拦截器,
        // 如果是正式上线了isDebug该false,就不打印日志
        if (Constants.isDebug) {
            builder.addInterceptor(new LoggingInterceptor());
        }
        return builder.build();
    }

    /**
     * 请求的修改设置
     */
/*    public static class HeadersInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            //sp:shareprefrences
            String token = (String) SpUtil.getParam(Constants.TOKEN,"");
            //LogUtils.print("token:"+token);
            Request request = chain.request().newBuilder()
                    .addHeader("Accept-Encoding", "identity")
                    .build();
            return chain.proceed(request);
        }
    }*/

    /**
     * 固定模板
     */
    private class MyCacheinterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            //这里就是说判读我们的网络条件,要是有网络的话我么就直接获取网络上
            // 面的数据,要是没有网络的话我么就去缓存里面取数据
            if (!SystemUtil.isNetworkConnected()) {
                request = request
                        .newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)//强制使用缓存
                        .build();
            }
            Response originalResponse = chain.proceed(request);
            if (SystemUtil.isNetworkConnected()) {
                int maxAge = 0;
                // 有网络时, 不缓存, 最大保存时长为0
                return originalResponse.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public ,max-age=" + maxAge)
                        .build();
            } else {
                //s秒
                int maxStale = 60 * 60 * 24;
                return originalResponse.newBuilder()
                        .removeHeader("Pragma")
                        //这里的设置的是我们的没有网络的缓存时间,
                        // 想设置多少就是多少。
                        .header("Cache-Control", "public, only-if-cached," +
                                " max-age=" + maxStale)
                        .build();
            }

        }
    }

    //日志拦截器
    public class LoggingInterceptor implements Interceptor {
        private static final String TAG = "LoggingInterceptor";

        @Override
        public Response intercept(Chain chain) throws IOException {
            //通过系统时间的差打印接口请求的信息
            long time = System.nanoTime();
            Request request = chain.request();
            StringBuilder sb = new StringBuilder();
            //把get和post请求提交的参数打印出来
            if ("GET".equals(request.method())) { // GET方法
                HttpUrl httpUrl = request.url().newBuilder().build();
                sb.append("GET,");
                // 打印所有get参数
                Set<String> paramKeys = httpUrl.queryParameterNames();
                for (String key : paramKeys) {
                    String value = httpUrl.queryParameter(key);
                    sb.append(key + ":" + value + ",");
                }

            } else if ("POST".equals(request.method())) { // POST方法
                sb.append("POST,");
                // FormBody和url不太一样,若需添加公共参数,需要新建一个构造器
                /*FormBody.Builder bodyBuilder = new FormBody.Builder();
                // 把已有的post参数添加到新的构造器
                if (request.body() instanceof FormBody) {
                    FormBody formBody = (FormBody) request.body();
                    for (int i = 0; i < formBody.size(); i++) {
                        bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
                    }
                }

                // 这里可以添加一些公共post参数
                bodyBuilder.addEncoded("key_xxx", "value_xxx");
                FormBody newBody = bodyBuilder.build();

                // 打印所有post参数
                for (int i = 0; i < newBody.size(); i++) {
                    Log.d("TEST", newBody.name(i) + " " + newBody.value(i));
                }*/

                if (request.body() instanceof FormBody) {
                    FormBody formBody = (FormBody) request.body();
                    for (int i = 0; i < formBody.size(); i++) {
                        sb.append(formBody.name(i)+":"+formBody.value(i)+",");
                    }
                }

            }

            LogUtil.logd("Request:", String.format("Sending request %s %n %s %n%s", request.url(), sb.toString(),request.headers()));
            Response response = chain.proceed(request);
            long now = System.nanoTime();
            LogUtil.logd("Received:", String.format("Received response for %s in %.1fms%n%s", response.request().url(), (now - time) / 1e6d, response.headers()));


            //response.body().string(); 只能使用一次,使用之后就关流了
            LogUtil.logd("Data:", response.peekBody(4096).string());
            return response;
        }
    }

    volatile ApiService mApiService;
    //创建Retrofit请求数据接口,以前这么写是因为baseurl不固定
    public ApiService getApiService(){
        if (mApiService == null){
            synchronized (HttpUtil.class){
                if (mApiService == null){
                    mApiService = mRetrofitBuilder.baseUrl(ApiService.url)
                            .build()
                            .create(ApiService.class);
                }
            }
        }
        return mApiService;
    }

    //简单的日志拦截器
    class SimpleLogInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            Log.d("SimpleLogInterceptor", "url: "+request.url()+
                    ",data:"+response.peekBody(4096).string());
            return response;
        }
    }
}
public class RxUtils {
    public static <T> FlowableTransformer<T,T> rxSchedulerHelper(){
        //compose简化线程
        return new FlowableTransformer<T, T>() {
            @Override
            public Flowable<T> apply(Flowable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())//被观察者执行的线程
                        .observeOn(AndroidSchedulers.mainThread());//观察者执行的线程
            }
        };
    }
    public static <T> ObservableTransformer<T,T> rxObserableSchedulerHelper(){
        //compose 简化线程
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }
}
public class SystemUtil {

    /**
     * 检查WIFI是否连接
     */
    public static boolean isWifiConnected() {
        ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.sContext.
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo wifiInfo = connectivityManager
                .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        return wifiInfo != null;
    }
    /**
     * 检查手机网络(5G/4G/3G/2G)是否连接
     */
    public static boolean isMobileNetworkConnected() {
        ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.sContext.
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo mobileNetworkInfo = connectivityManager
                .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        return mobileNetworkInfo != null;
    }
    /**
     * 检查是否有可用网络
     */
    public static boolean isNetworkConnected() {
        ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.sContext.
                getSystemService(Context.CONNECTIVITY_SERVICE);
        return connectivityManager.getActiveNetworkInfo() != null;
    }

    /**
     * 保存文字到剪贴板
     * @param context
     * @param text
     */
    public static void copyToClipBoard(Context context, String text) {
        ClipData clipData = ClipData.newPlainText("url", text);
        ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        manager.setPrimaryClip(clipData);
        Toast.makeText(context,"已复制到剪贴板", Toast.LENGTH_SHORT).show();
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dp2px(float dpValue) {
        final float scale = BaseApp.sContext.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dp(float pxValue) {
        final float scale = BaseApp.sContext.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static int sp2px(float spValue) {
        float scaledDensity = BaseApp.sContext.getResources().getDisplayMetrics().scaledDensity;
        return (int)(spValue * scaledDensity + 0.5F);
    }

    public static int px2sp(float pxValue) {
        float scaledDensity = BaseApp.sContext.getResources().getDisplayMetrics().scaledDensity;
        return (int)(pxValue / scaledDensity + 0.5F);
    }

    /**
     * 获取进程号对应的进程名
     *
     * @param pid 进程号
     * @return 进程名
     */
    public static String getProcessName(int pid) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline"));
            String processName = reader.readLine();
            if (!TextUtils.isEmpty(processName)) {
                processName = processName.trim();
            }
            return processName;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException exception) {
                exception.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 关闭软键盘
     *
     * @param activity
     */
    public static void closeKeyBoard(Activity activity) {
        InputMethodManager im = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);

        if (activity.getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
            if (activity.getCurrentFocus() != null)
                im.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);
        }

    }
}

具体代码参照:MVP抽取

相关文章

  • MVP抽取

    为什么要抽取? 每一个页面都用到同样的内容,每次都写同样的代码,浪费;规定代码的编写规范;多人开发维护变得简单。 ...

  • Mvp抽取

    为什么要抽取? 每一个页面都用到同样的内容,每次都写同样的代码,浪费;规定代码的编写规范;多人开发维护变得简单。 ...

  • MVP抽取

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

  • MVP抽取

    为什么要抽取? 每一个页面都用到同样的内容,每次都写同样的代码,浪费; 规定代码的编写规范; 多人开发维护变得简单...

  • MVP抽取

    一、抽取原因 每一个页面都用到同样的内容,每次都写同样的代码,浪费;规定代码的编写规范;多人开发维护变得简单。 二...

  • MVP 终极抽取(下)

    流程图: 通过MVP终极抽取(上)让我们可以知道Model 的抽取。那么开始view ,presenter 的抽取...

  • 自制MVP基类框架依赖库和工具类(自用)

    抽取 除了mvp层的抽取,还有对Activity、Adapter、Fragment的抽取 工具类 验证码工具类:C...

  • MVP抽取.md

    让子类的工作模式都按父类的执行 一个抽象类公开定义了执行它的方法的方式 网络抽取 HttpManager RxUt...

  • Mvp_抽取

    1.BaseActivity层 2.BaseCallBack层(与BaseView层相同) 3.Baseview层...

  • MVP终极抽取(上)

    流程图: 首先创建model 层 并且对他的请求参数,网络请求,数据参数,进行封装,这样可以减小相似代码。更简洁。...

网友评论

    本文标题:MVP抽取

    本文链接:https://www.haomeiwen.com/subject/guzrzhtx.html