MVPArch - Android MVP 快速开发框架

MVPArch


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

  • 封装Activity/Fragment基类-BaseActivity/BaseFragment(Fragment懒加载开关配置)
  • 封装MVP模式Activity/Fragment基类-BaseMVPActivity/BaseMVPFragment,V与P层生命周期监听和绑定,解决诸多内存泄漏问题
  • 使用 LoadingStateView实现可定制化的页面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:1.0.8-beta.1'
	}

效果图


功能实现


  1. UILog、UIToast

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

package com.huangxiaoliang.mvparchdemo.util;

import android.util.Log;

import com.huangxiaoliang.mvplib.manager.MVPArchConfig;
import com.huangxiaoliang.mvplib.manager.log.UILog;

/**
 * @author : HHotHeart
 * @date : 2021/9/24 10:01
 * @desc : 自定义代理
 */
public class CustomLogDelegate implements UILog.LogDelegate {

    @Override
    public String getTag() {
        return "日志Tag";
    }

    @Override
    public UILog.LogDelegate init() {
        //做一些初始化工作
        return this;
    }

    @Override
    public void v(String tag, String msg, Object... obj) {
        Log.v(tag, msg);
    }

    @Override
    public void d(String tag, String msg, Object... obj) {
        //自己的Log库
        Log.d(tag, msg);

    }

    @Override
    public void i(String tag, String msg, Object... obj) {
        //自己的Log库
        Log.i(tag, msg);

    }

    @Override
    public void w(String tag, String msg, Object... obj) {
        //自己的Log库
        Log.w(tag, msg);

    }

    @Override
    public void e(String tag, String msg, Object... obj) {
        //自己的Log库
        Log.e(tag, msg);

    }

    @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) {
        //自己的Log库

    }
}

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

     MVPArchConfig.getInstance().setLogDelegate(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、EventBusImpl

     MVPArchConfig.getInstance().setImageLoader(IImageLoader imageLoader)
     MVPArchConfig.getInstance().setEventBus(IEventBus eventBus);

两者调用方式

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

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

        MVPArchConfig.getInstance()
                .setLogDelegate(new CustomLogDelegate().init())
                .setLoggable(BuildConfig.DEBUG)
                .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_height1)
                        .setTittleBarBgColor(Color.WHITE)
                        .setRightIconVisible(false)
                        .setBottomLineColor(Color.LTGRAY)
                        .setBottomLineHeight(0.5f));

        LoadingStateView.setViewDelegatePool(pool ->
                pool.register(new GLoadingViewDelegate(), new GErrorViewDelegate(), new GEmptyViewDelegate()));

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

        <meta-data
            android:name="MVPArch.LCEDelegate"
            android:value="com.huangxiaoliang.mvparchdemo.util.CustomLCEDelegate" />
package com.huangxiaoliang.mvparchdemo.util;

import android.content.Context;
import android.text.TextUtils;
import android.view.View;

import com.dylanc.loadingstateview.LoadingStateView;
import com.huangxiaoliang.mvplib.manager.lcet.GTitleBarViewDelegate;
import com.huangxiaoliang.mvplib.manager.lcet.ILCEView;
import com.huangxiaoliang.mvplib.manager.lcet.ITitleView;
import com.kaopiz.kprogresshud.KProgressHUD;

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/LoadingStateView
    private LoadingStateView mLoadingHelper = null;
    //加载框 https://github.com/Kaopiz/KProgressHUD
    private KProgressHUD mKProgressHUD = null;


    public CustomLCEDelegate(View rootView) {
        mContext = rootView.getContext();
        mLoadingHelper = new LoadingStateView(rootView);
        mRealRootView = mLoadingHelper.getDecorView();
    }

    /**
     * 获取真正的RootView
     *
     * @return
     */
    @Override
    public View getRealRootView() {
        return mRealRootView;
    }

    /**
     * 设置标题
     * 如果页面滑动对标题有动作,不建议使用LoadingHelper设置标题
     *
     * @param titleParam
     */
    @Override
    public void setTitleBar(ITitleView titleParam) {
        mLoadingHelper.setHeaders(new GTitleBarViewDelegate(titleParam));
    }

    /**
     * 空数据视图
     * 调用此方法确保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 LoadingStateView getLoadingHelper() {
        return mLoadingHelper;
    }

    public KProgressHUD getKProgressHUD() {
        return mKProgressHUD;
    }
}

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

package com.huangxiaoliang.mvparchdemo.activity;

import android.graphics.Color;
import android.os.Bundle;
import android.view.View;

import com.huangxiaoliang.mvparchdemo.R;
import com.huangxiaoliang.mvplib.manager.lcet.TitleParam;
import com.huangxiaoliang.mvplib.manager.toast.UIToast;
import com.huangxiaoliang.mvplib.mvp.BaseActivity;
import com.huangxiaoliang.mvplib.manager.imageloader.IImageLoader;
import com.huangxiaoliang.mvplib.manager.imageloader.ILFactory;

import androidx.annotation.Nullable;

/**
 * @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 onBusiness(Bundle savedInstanceState) {
        ILFactory.getLoader().loadNet(findViewById(R.id.imageView1),
                "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2020-06-29%2F5ef9b315417b8.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657890578&t=11177abaff83a7971b98f5a40b97d1b2",
                IImageLoader.HOptions.defaultOptions());
    }
}

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

package com.huangxiaoliang.mvparchdemo.activity;

import android.os.Bundle;

import com.dylanc.loadingstateview.LoadingStateView;
import com.huangxiaoliang.mvparchdemo.R;
import com.huangxiaoliang.mvparchdemo.delegate.CLoadingViewDelegate;
import com.huangxiaoliang.mvparchdemo.listener.NetCallback;
import com.huangxiaoliang.mvparchdemo.util.CustomLCEDelegate;
import com.huangxiaoliang.mvparchdemo.util.HttpUtils;
import com.huangxiaoliang.mvplib.manager.toast.UIToast;
import com.huangxiaoliang.mvplib.mvp.BaseActivity;

import androidx.annotation.Nullable;

/**
 * @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 onBeforeBusiness(@Nullable Bundle savedInstanceState) {
        LoadingStateView loadingHelper = ((CustomLCEDelegate) getLCEDelegate()).getLoadingHelper();
        loadingHelper.register(new CLoadingViewDelegate());
    }

    @Override
    protected void onBusiness(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() {
        getMvpView().stateLoadingView();
        getMvpModel().requestNet(new NetCallback<Long>() {
            @Override
            public void onSubscribe(Disposable d) {
                getMvpView().addDispose(d);
            }

            @Override
            public void onSuccess(Long o) {
                getMvpView().stateContentView();
                getMvpView().showToast();
            }

            @Override
            public void onFailure(String msg) {
                getMvpView().stateErrorView();
                UIToast.showShort(msg);
            }
        });
    }

    @Override
    public void onReload() {
        getMvpView().stateLoadingView();
        getMvpModel().requestNet(new NetCallback<Long>() {
            @Override
            public void onSubscribe(Disposable d) {
                getMvpView().addDispose(d);
            }

            @Override
            public void onSuccess(Long aLong) {
                getMvpView().stateContentView();

            }

            @Override
            public void onFailure(String msg) {
                getMvpView().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 ooBusiness(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)));

        getMvpPresenter().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任务时,应手动调用方法

 		getMvpView().addDispose(d);

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

		observable.compose(bindUntilEvent(ActivityEvent event));

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

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄小梁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值