自定義註解在MVP中的使用

在Mvp架構中Activity需要創建Presenter對象,並處理與Presenter的綁定、解除綁定關係,這是View層公共的邏輯,可以把這些邏輯抽取到Base中統一處理,然而一個Activity中可能需要創建多個Presenter對象,這就需要在Activity中創建一個List列表來存儲這個頁面中所有的Presenter對象,在具體的子類Activiy中並不確定到底有多少個Presenter對象,解決這個問題可以爲子類提供一個抽象方法,通過實現這個抽象方法子類Activity將所有創建的Presenter對象手動添加進去,這樣操作起來會有點麻煩,而且在實際編碼過程中還經常會忘記這步操作。這裏通過自定義註解的方式來解決這個問題,具體就是通過爲Presenter變量添加註解,在基類中解析註解信息自動創建Presenter對象、自動維護List列表和相關邏輯,做到子類完全不用關心這些操作,下面看下代碼實現:

1、創建自定義註解類

package com.znh.commonlib.base.inject;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by znh on 2019/6/3
 */
@Target(ElementType.FIELD) //註釋1
@Retention(RetentionPolicy.RUNTIME) //註釋2
public @interface InjectPresenter {

}

上述代碼就定義了一個註解InjectPresenter,註釋1代表該註解作用於成員變量,註釋2代表該註解是運行時註解。

2、創建基類BaseMvpActivity處理相關邏輯

package com.znh.commonlib.base;

import android.os.Bundle;
import android.support.annotation.Nullable;

import com.znh.commonlib.base.inject.InjectPresenter;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by znh on 2019/6/3
 * <p>
 * MvpActivity基類
 */
public abstract class BaseMvpActivity extends RxAppCompatActivity implements IBaseView {

    //存儲當前頁面中對應的所有的Presenter
    public List<BasePresenter> mPresenters;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());

        //處理Presenter的創建和綁定
        mPresenters = new ArrayList<>();
        createAndBindPresenter();

        initView();
        initData();
    }

    /**
     * 獲取頁面佈局id
     *
     * @return
     */
    public abstract int getLayoutId();

    /**
     * 初始化View
     */
    protected abstract void initView();

    /**
     * 初始化數據
     */
    protected abstract void initData();

    /**
     * 創建並綁定Presenter
     */
    public void createAndBindPresenter() {
        //通過反射注入Presenter
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
            if (injectPresenter != null) {
            	//註釋3
                if (!BasePresenter.class.isAssignableFrom(field.getType())) {
                    throw new RuntimeException("InjectPresenter annotations have incorrect field types and can only be used for BasePresenter and its subclasses");
                }
                Class<? extends BasePresenter> basePresenterClazz = (Class<? extends BasePresenter>) field.getType();

                try {
                    //註釋4 創建對象
                    BasePresenter basePresenter = basePresenterClazz.newInstance();
                    basePresenter.attachView(this);

                    //設置字段
                    field.setAccessible(true);
                    field.set(this, basePresenter);

                    //註釋5 添加Presenter
                    mPresenters.add(basePresenter);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 解綁Presenter
     */
    public void unBindPresenter() {
        for (BasePresenter basePresenter : mPresenters) {
            basePresenter.detachView();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unBindPresenter();
    }
}

在onCreate方法中創建mPresenters列表用來存儲頁面中所有的Presenter對象,然後調用createAndBindPresenter方法創建頁面中所有的Presenter對象,並處理綁定邏輯,在註釋3處校驗註解作用的字段是否是BasePresenter類型的,如果不是就拋出異常,註釋4處通過反射創建出Presenter實例對象並和View進行綁定,註釋5處將創建的Presenter實例對象添加到集合列表中進行管理。在Activity的onDestroy方法中調用unBindPresenter方法對所有跟這個Activity有綁定關係的Presenter進行解除綁定,防止內存泄漏。

3、在代碼中直接使用註解

package com.znh.commonlib.base;

import com.znh.commonlib.base.inject.InjectPresenter;

/**
 * Created by znh on 2019/6/3
 * <p>
 * 測試頁面
 */
public class TestActivity extends BaseMvpActivity {

    @InjectPresenter
    private Presenter1 mPresenter1;

    @InjectPresenter
    private Presenter2 mPresenter2;

    @InjectPresenter
    private Presenter3 mPresenter3;
    
    public void loadData() {
        mPresenter1.loadData();
        mPresenter2.loadData();
        mPresenter3.loadData();
    }

	...........
}

在Activity子類中如果需要使用哪個Presenter,就直接將對應的Presenter聲明爲成員變量併爲其添加@InjectPresenter註解,就可以直接在代碼中調用對應Presenter的方法,不需要關心其他的操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章