安卓Mvp架构(java、kotlin)

疫情刚好静下心来回归过去的工作,工作以后往往都是往前跑,其实偶尔多回归下技术,沉淀下来,这是博主抽离的mvp架构,本章源码linkhttps://github.com/apple317/AppleMvp,分为mvp_java和mvp_kotlin两个分支版本,网络组件com.applehsp.http:AppleHttpJava:1.0.0,mvp地址依懒com.applehsp.mvp:MvpKotlin:1.0.7,组件化demo例子请看添加链接描述,源demo源码添加链接描述,需要请评论联系博主,麻烦动动手点个星,万分感谢。
1.支持rxjava、RxLifecycle特性
2.支持加载中过渡扩展
3.支持java、kotlin双版本mvp
4.支持多个Presenter共用
5.插拔式的AOP设计理念
6.支持fragement、activity调用
7.支持依懒引入
8.支持androidx、android两个版本

1.Mvp使用说明

1.1 java-mvp库依懒说明

       第一步引入依懒,本库已发到jenter中心,请记得在根工程中添加jenter():
       第二步添加依懒java-mvp版本库
 implementation 'com.applehsp.mvp:MvpJava:1.0.7'

1.2 java-mvp使用说明

public class SplashPresenter extends BasePresenter<SplashView> {
    public SplashPresenter() {
    }
    /**
     * 广告方法
     * @param message
     */
    public void advertList(String message) {
        getView().advertList(message);
    }
}
public interface SplashView extends IBaseView {
    void advertList(String advert);
}
public class MainActivity extends BaseMvpActivity implements SplashView, MainView{
    @BindView(R.id.btnSync)
    Button btnSync;
    @BindView(R.id.btnAdvert)
    Button btnAdvert;
    //通过注释,通过运行时动态代理p-->v关联,支持多个p注入
    @CreatePresenterAnnotation(SplashPresenter.class)
    SplashPresenter splashPresenter;
    @CreatePresenterAnnotation(MainPresenter.class)
    MainPresenter mainPresenter;

    @Override
    public int setLayoutId() {
        return R.layout.activity_main;
    }
    
    @Override
    protected void initData() {

    }

    @Override
    protected void initView(Bundle savedInstanceState) {
        ButterKnife.bind(this);
    }

    @Override
    public void appSync(String msg) {
        btnSync.setText(msg);
    }

    @Override
    public void advertList(String advert) {
        btnAdvert.setText(advert);
    }


    @OnClick({R.id.btnSync, R.id.btnAdvert})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.btnSync:
                mainPresenter.appSync("首页初始化");
                break;
            case R.id.btnAdvert:
                splashPresenter.advertList("启动页初始化");
                break;
        }
    }
}

1.3 kotlin版本库依懒说明

       第一步引入依懒,本库已发到jenter中心,请记得在根工程中添加jenter():
       第二步添加依懒java-kotlin版本库
implementation 'com.applehsp.mvp:MvpKotlin:1.0.0'
```java

## 1.4 kotlin版本库使用说明

```kotlin
class SplashPresenter : BasePresenter<SplashView>() {
    /**
     * 广告方法
     * @param message
     */
    fun advertList(message: String) {
        view!!.advertList(message)
    }
}
interface SplashView : IBaseView {
    fun advertList(advert: String)
}
class MainActivity : BaseMvpActivity(), SplashView, MainView {

    @CreatePresenterAnnotation(SplashPresenter::class)
    var splashPresenter: SplashPresenter? = null
    @CreatePresenterAnnotation(MainPresenter::class)
    var mainPresenter: MainPresenter? = null

    override fun setLayoutId(): Int {
        return R.layout.activity_main
    }

    override fun initData() {
        btnAdvert.setOnClickListener { splashPresenter?.advertList("kotlin 广告") }
        btnSync.setOnClickListener { mainPresenter?.appSync("kotlin 同步") }
    }

    override fun appSync(msg: String) {
        btnSync.text = msg
    }
    override fun advertList(advert: String) {
        btnAdvert.text = advert
    }
    override fun initView(savedInstanceState: Bundle?) {
    }
}
class HomeFragment : BaseMvpFragmentX() {
    override fun initView() {}
    override fun initData(savedInstanceState: Bundle?) {
    }

    override fun showProgress(loading: Boolean) {
    }

    override fun onResume() {
        super.onResume()
    }

    override fun setLayoutId(): Int {
        return R.layout.hot
    }
}
class UserFragment : BaseMvpFragment(){

    override fun initData() {
    }

    override fun initView() {
    }

    override fun setLayoutId(): Int {
        return R.layout.activity_main
    }

}

两个版本完全调用写法一样,保证业务层低转化成本,p层方法可以自由定义扩张,只需要定义view的回传的方法,p层耦合很低,我们可以在开发业务逻辑最小颗粒化,而代码量很少,在下面也会对比几个mvp,么有对比就么有优势和伤害。

2.Mvp原理讲解

在这里开篇首先说一下,每个架构其实原理核心代理不会超过1000代码,这里只讲解原理核心思想,欢迎大家一起集思广益,多多点星,多多分享,博主马上会研究flutter,会赚到flutter插件研发,如果要想封装一个库分享,最好先github找到对应的库看个三四个,这样对你帮助真的很大,这是博主好多年的心得。

2.1 java-mvp原理讲解

这里使用是注解,运行时的获取对应属性方法和值,然后通过反射注释类相关对应BasePresenter,然后newInstance实力化对象,Presenter和view必须要弱引用,例如:
页面销毁,网络请求可能在进行中,那么问题就来了会导致空指针到处崩溃,怎么解决这个疼点,就要取消这两个关联。
rxjava怎么办,这个也会崩溃,放心这个博主想到了,支持rxjava、支持rxlifecycle3版本特性。

@Retention(RUNTIME)
@Target(FIELD)
public @interface CreatePresenterAnnotation {
    Class<? extends BasePresenter> value();
}
/**
     * 支持rxjava,绑定生命周期 
     * 预留支持加载过渡效果实现
     * @return
     */
    @Override
    public <T> LifecycleTransformer<T> bindLifeycle(boolean loading) {
        if (loading) {
            showProgress();
        }
        return this.bindToLifecycle();
    }
	//通过弱引用来存储view层对象。
    private WeakReference<V> mWeakReference;
    private V mProxyView;
    /**
     * 关联V层和P层
     *
     */
    public void attatchView(V v) {
        mWeakReference = new WeakReference<>(v);
        MvpViewHandler viewHandler = new MvpViewHandler(mWeakReference.get());
        //这里重点核心v通过动态代理实例化view对象
        mProxyView = (V) Proxy.newProxyInstance(v.getClass().getClassLoader(), v.getClass().getInterfaces(), viewHandler);
    }
    /**
     * 断开V层和P层
     * 在Acitivity的onDestory()中调用
     */
    public void detachView() {
        if (isViewAttached()) {
            mWeakReference.clear();
            mWeakReference = null;
        }
    }
  //这里通过工厂设计模式,通过反射机制实例化对应Presenter对象。
   public static <V extends IBaseView, P extends BasePresenter<V>> MvpPresenterFactroyImpl creater(Context context) {
        //拿到创建presenter的注解
        List<BasePresenter> currentPresenter = new ArrayList<>();
        Log.e("HU","MvpPresenterFactroyImpl=creater==="+context);
        try{
            Field[] fields = context.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(CreatePresenterAnnotation.class)) {
                    Log.e("HU","MvpPresenterFactroyImpl=11111==="+fields);
                    CreatePresenterAnnotation address = field.getAnnotation(CreatePresenterAnnotation.class);
                    Class<? extends BasePresenter> presenter = address.value();
                    try {
                        field.setAccessible(true); //设置属性值的访问权限
                        BasePresenter presenter1 = presenter.newInstance();
                        field.set(context, presenter1); //将查找到的view指定给目标对象object
                        currentPresenter.add(presenter1);
                    } catch (IllegalAccessException e) {
                        Log.e("HU","MvpPresenterFactroyImpl=IllegalAccessException==="+context);
                        throw new RuntimeException(e);
                    } catch (InstantiationException e) {
                        Log.e("HU","MvpPresenterFactroyImpl=InstantiationException==="+context);

                        e.printStackTrace();
                    }
                }
            }
        }catch (Exception e){
            Log.e("HU","MvpPresenterFactroyImpl=2222==="+context);
            e.printStackTrace();
        }
        return new MvpPresenterFactroyImpl(currentPresenter);
    }

2.2 kotlin-mvp原理讲解

  //请在https://github.com/apple317/AppleMvp代码库下找MvpPresenterFactroyImpl.kt文件
  fun  mvpCreate(context: Context): MvpPresenterFactroyImpl{ 
  //拿到创建presenter的注解
            val currentPresenter: ArrayList<BasePresenter<out IBaseView>> = ArrayList<BasePresenter<out IBaseView>>()
            Log.e("HU", "MvpPresenterFactroyImpl=creater===$context")
            try {
                val fields = context.javaClass.declaredFields
                for (field in fields) {
                    if (field.isAnnotationPresent(CreatePresenterAnnotation::class.java)) {
                        Log.e("HU", "MvpPresenterFactroyImpl=11111===$fields")
                        val address = field.getAnnotation(CreatePresenterAnnotation::class.java)
                        val presenter: KClass<out BasePresenter<out IBaseView>> = address.value
                        try {
                            field.isAccessible = true //设置属性值的访问权限
                            val presenter1: BasePresenter<out IBaseView> = presenter.java.newInstance()!!
                            field[context] = presenter1 //将查找到的view指定给目标对象object
                            currentPresenter.add(presenter1)
                        } catch (e: IllegalAccessException) {
                            Log.e("HU", "MvpPresenterFactroyImpl=IllegalAccessException===$context")
                            throw RuntimeException(e)
                        } catch (e: InstantiationException) {
                            Log.e("HU", "MvpPresenterFactroyImpl=InstantiationException===$context")
                            e.printStackTrace()
                        }
                    }
                }
            } catch (e: Exception) {
                Log.e("HU", "MvpPresenterFactroyImpl=2222===$context")
                e.printStackTrace()
            }
            return MvpPresenterFactroyImpl(currentPresenter)
        }
 @Suppress("UNCHECKED_CAST")
    fun attatchView(v: IBaseView) {
        weak.weakReference=WeakReference(v)
        val viewHandler = weak.weakReference.get()?.let { MvpViewHandler(it) }
        view = Proxy.newProxyInstance(this::class.java.classLoader, v.javaClass.interfaces,viewHandler)as V
    }
```kotlin
 private inner class MvpViewHandler internal constructor(private val mvpView: IBaseView) : InvocationHandler {
        @Throws(Throwable::class)
        override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? { //解决第三个问题,如果V层没被销毁, 执行V层的方法.
            try {
                if (isViewAttached) {
                    return method.invoke(mvpView, *args)
                }
            } catch (e: InvocationTargetException) {
                throw e.cause!!
            }
            //P层不需要关注V层的返回值
            return null
        }
    }

对比java和kotlin是不是很相似,虽然语法、特性不一样,但是实现思路是一样的,AOP的原理就是Java的动态代理机制,我们再也不需要关心业务层膨胀,而需要更改多处代码,而通过创建一个代理对象,业务层调用方法也是代理对象方法,真正做到解耦合。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader:      一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:           一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

3.Mvp对比伤害

3.1 第一对比例子

class HotTabPresenter:BasePresenter<HotTabContract.View>(),HotTabContract.Presenter {
    private val hotTabModel by lazy { HotTabModel() }
    override fun getTabInfo() {
        checkViewAttached()
        mRootView?.showLoading()
        val disposable = hotTabModel.getTabInfo()
                .subscribe({
                    tabInfo->
                    mRootView?.setTabInfo(tabInfo)
                },{
                    throwable->
                    //处理异常
                    mRootView?.showError(ExceptionHandle.handleException(throwable), ExceptionHandle.errorCode)
                })
        addSubscription(disposable)
    }
}
interface HotTabContract {
    interface View:IBaseView{
        /**
         * 设置 TabInfo
         */
        fun setTabInfo(tabInfoBean: TabInfoBean)
        fun showError(errorMsg:String,errorCode:Int)
    }
    interface Presenter:IPresenter<View>{
        /**
         * 获取 TabInfo
         */
        fun getTabInfo()
    }
}
class SearchActivity : BaseActivity(), SearchContract.View {

    private val mPresenter by lazy { SearchPresenter() }

    init {
        mPresenter.attachView(this)
        //细黑简体字体
        mTextTypeface = Typeface.createFromAsset(MyApplication.context.assets, "fonts/FZLanTingHeiS-L-GB-Regular.TTF")
    }
    }

3.2 第二对比例子

interface MainMVPPresenter<V : MainMVPView, I : MainMVPInteractor> : MVPPresenter<V, I> {

    fun refreshQuestionCards(): Boolean?
    fun onDrawerOptionAboutClick() : Unit?
    fun onDrawerOptionRateUsClick(): Unit?
    fun onDrawerOptionFeedClick(): Unit?
    fun onDrawerOptionLogoutClick()
}
class MainPresenter<V : MainMVPView, I : MainMVPInteractor> @Inject internal constructor(interactor: I, schedulerProvider: SchedulerProvider, disposable: CompositeDisposable) : BasePresenter<V, I>(interactor = interactor, schedulerProvider = schedulerProvider, compositeDisposable = disposable), MainMVPPresenter<V, I> {

    override fun onAttach(view: V?) {
        super.onAttach(view)
        getUserData()
        getQuestionCards()
    }

    override fun refreshQuestionCards() = getQuestionCards()

    override fun onDrawerOptionRateUsClick() = getView()?.openRateUsDialog()

    override fun onDrawerOptionFeedClick() = getView()?.openFeedActivity()

    override fun onDrawerOptionAboutClick() = getView()?.openAboutFragment()

    override fun onDrawerOptionLogoutClick() {
        getView()?.showProgress()
        interactor?.let {
            compositeDisposable.add(
                    it.makeLogoutApiCall()
                            .compose(schedulerProvider.ioToMainObservableScheduler())
                            .subscribe({
                                interactor?.performUserLogout()
                                getView()?.let {
                                    it.hideProgress()
                                    it.openLoginActivity()
                                }
                            }, { err -> println(err) }))
        }

    }

    private fun getQuestionCards() = interactor?.let {
        compositeDisposable.add(it.getQuestionCardData()
                .compose(schedulerProvider.ioToMainSingleScheduler())
                .subscribe({ questionCard ->
                    getView()?.let {
                        if (questionCard.isEmpty()) return@subscribe
                        else it.displayQuestionCard(questionCard)
                    }
                }, { err -> println(err) }))
    }


    private fun getUserData() = interactor?.let {
        val userData = it.getUserDetails()
        getView()?.inflateUserDetails(userData)
    }

}
class MainActivity : BaseActivity(), MainMVPView, NavigationView.OnNavigationItemSelectedListener,
        HasSupportFragmentInjector {

    @Inject
    internal lateinit var presenter: MainMVPPresenter<MainMVPView, MainMVPInteractor>
    @Inject
    internal lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
}
interface MainMVPView : MVPView {
    fun inflateUserDetails(userDetails: Pair<String?, String?>)
    fun displayQuestionCard(questionCard: List<QuestionCardData>)
    fun openLoginActivity()
    fun openFeedActivity()
    fun openAboutFragment()
    fun openRateUsDialog(): Unit?
    fun lockDrawer(): Unit?
    fun unlockDrawer(): Unit?
}
发布了50 篇原创文章 · 获赞 7 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/Apple_hsp/article/details/105436981