MVPArch


一个可有效提高Android开发效率的MVP框架

  • 封装Activity/Fragment基类-BaseActivity/BaseFragment(Fragment懒加载开关配置)
  • 封装MVP模式Activity/Fragment基类-BaseMVPActivity/BaseMVPFragment,V与P层生命周期监听和绑定,解决诸多内存泄漏问题
  • 使用 LoadingHelper实现可定制化的页面LCE视图
  • LoadingDialog加载框定制化,可随意切换
  • 使用TitleBar 实现可全局配置、页面可定制化的Title,不用每个页面写繁琐的xml代码
  • 沉浸式状态栏及状态栏颜色设置
  • 封装了Log、Toast,可自定义代理实现自己的Log、Toast
  • 封装了图片加载器、事件通知管理器,可通过配置切换

项目引入该库


在你的 Project build.gradle文件中添加:

allprojects {     repositories {     ...maven {      url 'https://jitpack.io' }}}

在你的 Module build.gradle文件中添加:

dependencies {             implementation 'com.github.HHotHeart:MVPArch:v1.0.2-beta1'}

效果图


功能实现


  1. UILog、UIToast

框架默认实现了UILog、UIToast的代理UILogDelegate、UIToastDelegate,如果不满足需求,可实现自己定义的代理(实现UILog.LogDelegate、UIToast.ToastDelegate即可),具体可参考框架的实现,这里简单实现了CustomLogDelegate

package com.littlejerk.mvparch.util;import android.util.Log;import com.littlejerk.library.manager.MVPArchConfig;import com.littlejerk.library.manager.log.UILog;/** * @author : HHotHeart * @date : 2021/9/24 10:01 * @desc : 自定义代理 */public class CustomLogDelegate implements UILog.LogDelegate {         boolean isDebug = true;    @Override    public String getTag() {             return "日志Tag";    }    @Override    public UILog.LogDelegate init() {             //做一些初始化工作,如log日志的开关        isDebug = MVPArchConfig.getInstance().isLoggable();        return this;    }    @Override    public void v(String tag, String msg, Object... obj) {             if (isDebug) {                 Log.v(tag, msg);        }    }    @Override    public void d(String tag, String msg, Object... obj) {             //自己的Log库    }    @Override    public void i(String tag, String msg, Object... obj) {             //自己的Log库    }    @Override    public void w(String tag, String msg, Object... obj) {             //自己的Log库    }    @Override    public void e(String tag, String msg, Object... obj) {             //自己的Log库    }    @Override    public void xml(String tag, String msg) {             //自己的Log库    }    @Override    public void json(String tag, String msg) {             //自己的Log库    }    @Override    public void printErrStackTrace(String tag, Throwable throwable, Object... obj) {             //自己的Log库    }}

然后在Application中将代理设置给UILog

     UILog.setDelegate(new CustomLogDelegate().init());

Log日志开关可通过MVPArchConfig配置

     MVPArchConfig.getInstance().setLoggable(BuildConfig.DEBUG)

Toast的代理设置也一样,如

     UIToast.setDelegate(UIToast.ToastDelegate delegate);
  1. EventManager、ILFactory

框架默认实现了EventBusImpl事件通知和GlideLoader图片加载器,可以自由切换(实现IEventBus、IImageLoader接口即可),实现了之后可通过MVPArchConfig配置,如替换GlideLoader

     MVPArchConfig.getInstance().setImageLoader(IImageLoader imageLoader)

两者调用方式

     EventManager.getBus().post(IEventBus.AbsEvent event);     ILFactory.getLoader().loadNet(ImageView target, String url, IImageLoader.HOptions options);
  1. LCE-T

框架实现了L(加载视图)、C(内容视图)、E(错误视图、空视图)、T(标题)的逻辑处理,这里主要使用了两个库LoadingHelper和TitleBar ,具体实现原理可去Github上看看,框架可全局配置LCE-T,如

        //设置状态栏颜色、标题属性        MVPArchConfig.getInstance()                .setLightStatusBar(false)                .setStatusBarColor(Color.BLACK)                .setTitleParam(new TitleParam()                        .setLeftIcon(R.drawable.ic_arrow_back_black)                        .setMiddleTextSize(17f)                        .setMiddleTextColor(Color.BLACK)                        .setTitleBarHeight(R.dimen.title_bar_height)                        .setTittleBarBgColor(Color.WHITE)                        .setRightIconVisible(false)                        .setBottomLineColor(Color.LTGRAY)                        .setBottomLineHeight(0.5f));        //设置全局LCE        LoadingHelper.setDefaultAdapterPool(adapterPool -> {                 adapterPool.register(ViewType.LOADING, new GLoadingAdapter());            adapterPool.register(ViewType.ERROR, new GErrorAdapter());            adapterPool.register(ViewType.EMPTY, new GEmptyAdapter());            return Unit.INSTANCE;        });

其中GLoadingAdapter、GErrorAdapter、GEmptyAdapter是框架实现的默认全局LCE,可参考将其替换成自己项目的LCE。因为LCE-T的设置是通过LCEDelegate(实现ILCEView)实现的,要想改变代理实现,可自定义代理CustomLCEDelegate实现ILCEView接口,然后通过清单文件AndroidManifest.xml去配置自定义的代理,如

        <meta-data            android:name="MVPArch.LCEDelegate"            android:value="com.littlejerk.mvparch.util.CustomLCEDelegate" />
package com.littlejerk.mvparch.util;import android.content.Context;import android.text.TextUtils;import android.view.View;import com.dylanc.loadinghelper.LoadingHelper;import com.dylanc.loadinghelper.ViewType;import com.kaopiz.kprogresshud.KProgressHUD;import com.littlejerk.library.manager.lcet.ITitleView;import com.littlejerk.library.manager.lcet.TitleBarAdapter;import com.littlejerk.library.manager.lcet.ILCEView;import org.json.JSONObject;/** * @author : HHotHeart * @date : 2021/7/9 17:36 * @desc : 自定义LCE代理类,需在清单文件注册meta */public class CustomLCEDelegate implements ILCEView {         private Context mContext = null;    private View mRealRootView = null;    //加载中、加载失败、空布局视图 https://github.com/DylanCaiCoding/LoadingHelper    private LoadingHelper mLoadingHelper = null;    //加载框 https://github.com/Kaopiz/KProgressHUD    private KProgressHUD mKProgressHUD = null;    public CustomLCEDelegate(View rootView) {             mContext = rootView.getContext();        mLoadingHelper = new LoadingHelper(rootView);        mRealRootView = mLoadingHelper.getDecorView();    }    /**     * 获取真正的RootView     *     * @return     */    @Override    public View getRealRootView() {             return mRealRootView;    }    /**     * 设置标题     * 如果页面滑动对标题有动作,不建议使用LoadingHelper设置标题     *     * @param titleParam     */    @Override    public void setTitleBar(ITitleView titleParam) {             mLoadingHelper.register(ViewType.TITLE, new TitleBarAdapter(titleParam));        mLoadingHelper.setDecorHeader(ViewType.TITLE);    }    /**     * 空数据视图     * 调用此方法确保mLoadingHelper注册对应的Adapter     */    @Override    public void stateEmptyView() {             mLoadingHelper.showEmptyView();    }    /**     * 错误视图     * 调用此方法确保mLoadingHelper注册对应的Adapter     */    @Override    public void stateErrorView() {             mLoadingHelper.showErrorView();    }    /**     * 加载中视图     * 调用此方法确保mLoadingHelper注册对应的Adapter     */    @Override    public void stateLoadingView() {             mLoadingHelper.showLoadingView();    }    /**     * 显示内容视图     */    @Override    public void stateContentView() {             mLoadingHelper.showContentView();    }    @Override    public void loadingDialogShow() {             loadingDialogShow(null);    }    @Override    public void loadingDialogShow(boolean cancelable) {             loadingDialogShow(null, cancelable);    }    @Override    public void loadingDialogShow(String msg) {             loadingDialogShow(msg, false);    }    @Override    public void loadingDialogShow(String msg, boolean cancelable) {             if (mKProgressHUD == null) {                 mKProgressHUD = KProgressHUD.create(mContext);        }        if (!TextUtils.isEmpty(msg)) {                 mKProgressHUD.setLabel(msg);        } else {                 mKProgressHUD.setLabel(null);        }        mKProgressHUD.setCancellable(cancelable);        mKProgressHUD.show();    }    /**     * 显示加载框的扩展     *     * @param msg     * @param cancelable     * @param extraData  拓展json字符串     */    @Override    public void loadingDialogShow(String msg, boolean cancelable, JSONObject extraData) {         }    /**     * 关闭加载框     */    @Override    public void loadingDialogDismiss() {             if (mKProgressHUD != null && mKProgressHUD.isShowing()) {                 mKProgressHUD.dismiss();        }    }    /**     * 释放资源     */    @Override    public void release() {             mKProgressHUD = null;        mContext = null;        mLoadingHelper = null;        mRealRootView = null;    }    public LoadingHelper getLoadingHelper() {             return mLoadingHelper;    }    public KProgressHUD getKProgressHUD() {             return mKProgressHUD;    }}

其中KProgressHUD 的加载框可改变,LoadingHelper不可更改(LCE的实现原理)。如果是页面定制化,应该如何呢?比如我们的标题

/** * @Author : HHotHeart * @Time : 2021/8/14 15:42 * @Description : 标题属性Demo */public class TitleDemoActivity extends BaseActivity {         @Override    protected void initContentView(@Nullable Bundle savedInstanceState) {             setContentView(R.layout.activity_title_demo, new TitleParam("Title Demo")                .setRightText("完成").setRightTextColor(Color.RED).setRightTextSize(17f)                .setOnTitleBarListener(new TitleParam.SimpleTitleBarListener() {                         @Override                    public void onLeftClick(View view) {                             finish();                    }                    @Override                    public void onRightClick(View view) {                             UIToast.showShort("点击完成");                    }                }));    }    @Override    protected void doBusiness(Bundle savedInstanceState) {             ILFactory.getLoader().loadNet(findViewById(R.id.imageView1),                "https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=218024201,1599297029&fm=26&gp=0.jpg",                IImageLoader.HOptions.defaultOptions());    }}

我们需要继承框架的BaseActivity,如果是MVP架构,可继承BaseMVPActivity(Fragment同理),页面的标题相关属性会覆盖全局配置的属性。当然,页面LCE的配置也是可覆盖全局配置的LCE,如

/** * @Author : HHotHeart * @Time : 2021/9/23 10:39 * @Description : 自定义加载布局Demo */public class CustomLCEActivity extends BaseActivity {         @Override    protected void initContentView(@Nullable Bundle savedInstanceState) {             setContentView(R.layout.activity_custom_lce, "自定义LCE");    }    @Override    public void doPreBusiness() {             LoadingHelper loadingHelper = ((CustomLCEDelegate) getLCEDelegate()).getLoadingHelper();        loadingHelper.register(ViewType.LOADING, new CLoadingAdapter());//        loadingHelper.register(ViewType.ERROR, "自定义的错误布局");//        loadingHelper.register(ViewType.EMPTY, "自定义的空布局");    }    @Override    protected void doBusiness(Bundle savedInstanceState) {             stateLoadingView();        HttpUtils.requestNet(this, new NetCallback<Long>() {                 @Override            public void onSuccess(Long aLong) {                     stateContentView();            }            @Override            public void onFailure(String msg) {                     stateErrorView();                UIToast.showShort(msg);            }        });    }}

更多用法查看代码。

  1. MVP模式

框架简易封装了MVP架构,使用了lifecycle管理Activity、Fragment和P层的生命周期,使用RxLifecycle管理Rxjava和Activity、Fragment的生命周期,有效地避免内存泄漏和P层销毁,延时任务造成的空指针问题,Activity(Fragment同理)业务逻辑实现的AContract管理MVP契约类

/** * @author : HHotHeart * @date : 2021/8/14 11:50 * @desc : 描述 */public class AContract {         public interface MyActivityModel {             void requestNet(NetCallback<Long> netCallback);    }    public interface MyActivityView extends IView {             void showToast();    }    public interface MyActivityPresenter {             void loadData();        default void onReload() {             }    }}

P层实现

/** * @Author : HHotHeart * @Time : 2021/6/11 11:53 * @Description : Activity Presenter */public class MvpDemoActivityPresenter extends BasePresenter<MvpDemoActivityModel, AContract.MyActivityView>        implements AContract.MyActivityPresenter {         private static final String TAG = "MvpDemoActivityPresenter";    @Override    public void loadData() {             getV().stateLoadingView();        getM().requestNet(new NetCallback<Long>() {                 @Override            public void onSubscribe(Disposable d) {                     getV().addDispose(d);            }            @Override            public void onSuccess(Long o) {                     getV().stateContentView();                getV().showToast();            }            @Override            public void onFailure(String msg) {                     getV().stateErrorView();                UIToast.showShort(msg);            }        });    }    @Override    public void onReload() {             getV().stateLoadingView();        getM().requestNet(new NetCallback<Long>() {                 @Override            public void onSubscribe(Disposable d) {                     getV().addDispose(d);            }            @Override            public void onSuccess(Long aLong) {                     getV().stateContentView();            }            @Override            public void onFailure(String msg) {                     getV().stateErrorView();                UIToast.showShort(msg);            }        });    }    @Override    public void onResume(@NonNull @NotNull LifecycleOwner owner) {             super.onResume(owner);    }    /**     * BasePresenter实现了和Activity或Fragment生命周期绑定,重写即可     *     * @param owner     */    @Override    public void onDestroy(@NonNull LifecycleOwner owner) {             super.onDestroy(owner);        UILog.d(TAG, TAG + " onDestroy被调用");    }}

V层实现

/** * @Author : HHotHeart * @Time : 2021/8/14 15:09 * @Description : Activity MVP例子 */public class MvpDemoActivity extends BaseMVPActivity<MvpDemoActivityPresenter> implements AContract.MyActivityView {         private static final String TAG = "MvpDemoActivity";    @BindView(R.id.imageView1)    ImageView mImageView1;    @Override    protected void initContentView(@Nullable Bundle savedInstanceState) {             setContentView(R.layout.activity_test_mvp, new TitleParam("Activity MVP模式"));    }    @Override    protected void doBusiness(Bundle savedInstanceState) {             ILFactory.getLoader().loadNet(mImageView1,                "https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=218024201,1599297029&fm=26&gp=0.jpg",                IImageLoader.HOptions.defaultOptions());        findView(R.id.btn_test, v -> UIToast.showLong("测试Toast"));        UILog.e(TAG, "isVisible:" + isVisible(findView(R.id.btn_test)));        getP().loadData();    }    @Override    public void showToast() {             UIToast.showLong("loadData加载完成");    }}

M层实现

/** * @Author : HHotHeart * @Time : 2021/6/11 15:46 * @Description : 描述 */public class MvpDemoActivityModel extends BaseModel implements AContract.MyActivityModel {         @Override    protected void initData() {             UIToast.showLong("测试TestModel");    }    @Override    public void requestNet(NetCallback<Long> netCallback) {             Observable.timer(2, TimeUnit.SECONDS)                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Observer<Long>() {                         @Override                    public void onSubscribe(@NonNull Disposable d) {                             if (netCallback != null) {                                 netCallback.onSubscribe(d);                        }                    }                    @Override                    public void onNext(@NonNull Long aLong) {                             if (netCallback != null) {                                 netCallback.onSuccess(aLong);                        }                    }                    @Override                    public void onError(@NonNull Throwable e) {                             if (netCallback != null) {                                 netCallback.onFailure(e.getMessage());                        }                    }                    @Override                    public void onComplete() {                             UILog.e("onComplete()");                    }                });    }}

BaseActivity和BaseFragment实现了Disposable的管理,每执行一个Rxjava任务时,应手动调用方法

 getV().addDispose(d);

添加任务的Disposable,在页面销毁时会把任务中断。除此之外还可以调用

observable.compose(bindUntilEvent(ActivityEvent event));

将Rxjava任务与页面生命周期绑定,ActivityEvent对应Actiivity的生命周期,如ActivityEvent.DESTROY,具体可查看RxLifecycle的用法。

后续会实现网络请求相关模块,将其请求与页面和Presneter生命周期完美结合起来,敬请期待!!!

Android 最强RecyclerView分割线XRecyclerViewDivider重磅来袭!!

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. python list.sort()根据多个关键字排序的方法实现
  3. android 全屏 webview 加载的h5的输入框,被键盘遮挡的解决
  4. Android(安卓)Window PhoneWindow DecorView
  5. Android(安卓)LinearLayout线性布局
  6. android APP隐私政策弹框的实现代码实例
  7. Android(安卓)实现 WheelView
  8. Android:简易弹幕效果实现,android弹幕
  9. android activity 实现半透明Translucent效果

随机推荐

  1. android源码下载方式
  2. Android Porting Environment Set
  3. Android调用.NET Webservice报org.ksoap2
  4. Android 组件资源库
  5. Android Studio & ADT 快捷键配置文件所
  6. Ionic 运行报错No resource identifier f
  7. Android Studio bug - attribute 'androi
  8. Android开发者实用代码片段 与大家分享
  9. Android内容提供者源码
  10. 从 Android Sample ApiDemos 中学习 andr