關(guān)于基類的那些事

安卓基礎(chǔ)開發(fā)庫(kù)诗力,讓開發(fā)簡(jiǎn)單點(diǎn)嘁酿。
DevRing & Demo地址https://github.com/LJYcoder/DevRing

前言

基類對(duì)于開發(fā)是很重要的一部分浙巫。在基類中一般可以進(jìn)行以下操作
1.把一些頻繁調(diào)用的代碼封裝起來(lái)潭流。
2.提供抽象方法給子類實(shí)現(xiàn)毙死,從而簡(jiǎn)化操作侵续、得到更直接的數(shù)據(jù)倔丈。
使用好基類可以減少代碼量憨闰,方便統(tǒng)一拓展,提高發(fā)開效率需五。

但由于Java單繼承的特性鹉动,有時(shí)別人提供的基類不一定能應(yīng)用到自己的項(xiàng)目里去,所以下面也會(huì)介紹通過LifecycleCallback的方法來(lái)實(shí)現(xiàn)Activity/Fragment基類的功能(該方式是從這里學(xué)習(xí)的)宏邮。


介紹

下面介紹demo中用到的基類泽示,如Activity基類、Fragment基類蜜氨、Adapter基類械筛、Presenter基類。
基類的具體實(shí)現(xiàn)請(qǐng)根據(jù)自己的需求來(lái)定制飒炎,下面僅供參考埋哟。

1. Activity基類

1.1 BaseActivity

public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements IBaseActivity {

    @BindColor(R.color.colorPrimary)
    int mColor;
    @Inject
    @Nullable
    protected P mPresenter;

    protected abstract int getContentLayout();//返回頁(yè)面布局id
    protected abstract void initView(Bundle savedInstanceState);//做視圖相關(guān)的初始化工作
    protected abstract void initData(Bundle savedInstanceState);//做數(shù)據(jù)相關(guān)的初始化工作
    protected abstract void initEvent();//做監(jiān)聽事件相關(guān)的初始化工作

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

        if (getContentLayout() != 0) {
            setContentView(getContentLayout());
            ButterKnife.bind(this);
        }
        initBarColor();//初始化狀態(tài)欄/導(dǎo)航欄顏色,需在設(shè)置了布局后再調(diào)用
        initView(savedInstanceState);
        initData(savedInstanceState);
        initEvent();
    }

    private void initBarColor() {
        ColorBar.newColorBuilder()
                .applyNav(true)
                .navColor(mColor).navDepth(0)
                .statusColor(mColor)
                .statusDepth(0)
                .build(this)
                .apply();
    }

    @Override
    public boolean isUseEventBus() {
        return false;
    }

    @Override
    public boolean isUseFragment() {
        return true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.destroy();
            mPresenter = null;
        }
    }
}

BaseActivity的作用如下:

  1. 重寫onCreate郎汪。
    這樣具體的Activity就不需要重寫onCreate()方法赤赊,而只需重寫getContentLayout()、initView(Bundle savedInstanceState);煞赢、initData(Bundle savedInstanceState)抛计、initEvent()并在其中進(jìn)行相應(yīng)的操作即可
  2. 設(shè)置狀態(tài)欄導(dǎo)航欄顏色。
    很多時(shí)候照筑,我們需要對(duì)app頂部的狀態(tài)欄以及底部的導(dǎo)航欄(含有虛擬按鍵的那一欄)進(jìn)行顏色設(shè)置從而實(shí)現(xiàn)沉浸式效果吹截。對(duì)于Andriod4.4、5.0版本凝危,它們?cè)O(shè)置顏色的方式有區(qū)別饭弓,所以需要做兼容處理。demo中使用的是UltimateBar開源庫(kù)媒抠,它內(nèi)部已經(jīng)做了兼容操作弟断,并提供了幾個(gè)方法來(lái)設(shè)置顏色,如不透明的趴生、半透明的阀趴、全透明的、隱藏等苍匆。
  3. 銷毀Presenter層對(duì)View層的引用刘急。
    這里涉及MVP開發(fā)模式,不了解的可以先點(diǎn)這里浸踩。由于Activity經(jīng)常需要銷毀Presenter層對(duì)View層的引用叔汁,所以移至基類中實(shí)現(xiàn)。
  4. 實(shí)現(xiàn)IBaseActivity接口
    實(shí)現(xiàn)該接口据块,以便通過Application.ActivityLifecycleCallbacks完成部分"基類操作"码邻,看完1.2你就懂了。

1.2 通過ActivityLifecycleCallbacks實(shí)現(xiàn)基類操作

顧名思義--- Activity生命周期回調(diào)另假。
當(dāng)注冊(cè)了該回調(diào)用像屋,每個(gè)Activity進(jìn)入相關(guān)生命周期時(shí)都會(huì)觸發(fā)相關(guān)回調(diào)。
所以我們可以通過Application.registerActivityLifecycleCallbacks(callback)方法注冊(cè)回調(diào)边篮,然后在ActivityLifecycleCallbacks里實(shí)現(xiàn)一些基類操作己莺。
不多說,直接上代碼戈轿。(代碼涉及了一些Dagger2凌受,可以點(diǎn)這里了解)

@Singleton
public class ActivityLifeCallback implements Application.ActivityLifecycleCallbacks {

    @Inject
    SimpleArrayMap<String, IActivityLife> mMapActivityLife;
    @Inject
    Provider<IActivityLife> mActivityLifeProvider;
    @Inject
    Lazy<FragmentLifeCallback> mFragmentLifeCallbackProvider;

    @Inject
    public ActivityLifeCallback() {
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
        if (activity instanceof IBaseActivity) {
            IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
            if (iActivityLife == null) {
                iActivityLife = mActivityLifeProvider.get();
                mMapActivityLife.put(activity.toString(), iActivityLife);
            }
            iActivityLife.onCreate(activity, bundle);
        }

        boolean isUseFragment = activity instanceof IBaseActivity ? ((IBaseActivity) activity).isUseFragment() : true;
        if (activity instanceof FragmentActivity && isUseFragment) {
            ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifeCallbackProvider.get(), true);
        }
    }

    @Override
    public void onActivityStarted(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onStart();
        }
    }

    @Override
    public void onActivityResumed(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onResume();
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onPause();
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onStop();
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onSaveInstanceState(bundle);
        }
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onDestroy();
        }
        mMapActivityLife.remove(activity.toString());
    }

}

我把各生命周期具體要做的事情放到ActivityLife里執(zhí)行了,下面貼上ActivityLife的代碼:

public class ActivityLife implements IActivityLife {

    private Activity mActivity;
    private final PublishSubject<ActivityEvent> mLifecycleSubject = PublishSubject.create();

    @Override
    public void onCreate(Activity activity, Bundle savedInstanceState) {
        mActivity = activity;

        mLifecycleSubject.onNext(ActivityEvent.CREATE);

        DevRing.activityStackManager().pushOneActivity(mActivity);

        if (((IBaseActivity) mActivity).isUseEventBus()) {
            DevRing.busManager().register(mActivity);
        }
    }

    @Override
    public void onStart() {
        mLifecycleSubject.onNext(ActivityEvent.START);
    }

    @Override
    public void onResume() {
        mLifecycleSubject.onNext(ActivityEvent.RESUME);
    }

    @Override
    public void onPause() {
        mLifecycleSubject.onNext(ActivityEvent.PAUSE);
    }

    @Override
    public void onStop() {
        mLifecycleSubject.onNext(ActivityEvent.STOP);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

    }

    @Override
    public void onDestroy() {
        mLifecycleSubject.onNext(ActivityEvent.DESTROY);

        DevRing.activityStackManager().popOneActivity(mActivity);

        if (((IBaseActivity) mActivity).isUseEventBus()) {
            DevRing.busManager().unregister(mActivity);
        }
        mActivity = null;
    }
}

接下來(lái)思杯,只要你的Activity實(shí)現(xiàn)了IBaseActivity接口胁艰,即可通過ActivityLifecycleCallbacks完成以下"基類操作":

  1. 幫助控制網(wǎng)絡(luò)請(qǐng)求的生命周期
    通過PublishSubject的操作智蝠,在onPause()/onStop()/onDestroy()中發(fā)射終止事件腾么,以便控制Retrofit網(wǎng)絡(luò)請(qǐng)求在頁(yè)面進(jìn)入特定狀態(tài)時(shí)終止。
  2. EventBus的訂閱/解除訂閱杈湾。
    根據(jù)isUseEventBus()來(lái)決定是否進(jìn)行EventBus的注冊(cè)/注銷解虱。
  3. Activity棧管理的入棧與出棧
    以便后面可通過ActivityStackManager進(jìn)行頁(yè)面銷毀工作漆撞。
  4. FragmentLifecycleCallbacks的注冊(cè)殴泰。
    根據(jù)isUseFragment()來(lái)決定是否注冊(cè)FragmentLifecycleCallbacks。

IBaseActivity接口代碼:

public interface IBaseActivity {
    /**
     * 該Activity是否訂閱事件總線
     * @return true則自動(dòng)進(jìn)行注冊(cè)/注銷操作浮驳,false則不注冊(cè)
     */
    boolean isUseEventBus();

    /**
     * 該Activity是否包含F(xiàn)ragment(是否注冊(cè)FragmentLifecycleCallbacks)
     * @return
     * 返回false則不注冊(cè)FragmentLifecycleCallbacks悍汛,也就是說{@link FragmentLifeCallback}中的操作不會(huì)進(jìn)行
     */
    boolean isUseFragment();
}

2. Fragment基類

2.1 BaseFragment

public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements IBaseFragment {

    protected Activity mActivity;
    //根布局視圖
    private View mContentView;
    //視圖是否已經(jīng)初始化完畢
    private boolean isViewReady;
    //fragment是否處于可見狀態(tài)
    private boolean isFragmentVisible;
    //是否已經(jīng)初始化加載過
    protected boolean isLoaded;
    //用于butterknife解綁
    private Unbinder unbinder;
    @Inject
    @Nullable
    protected P mPresenter;

    protected abstract boolean isLazyLoad();//是否使用懶加載 (Fragment可見時(shí)才進(jìn)行初始化操作(以下四個(gè)方法))
    protected abstract int getContentLayout();//返回頁(yè)面布局id
    protected abstract void initView();//做視圖相關(guān)的初始化工作
    protected abstract void initData();//做數(shù)據(jù)相關(guān)的初始化工作
    protected abstract void initEvent();//做監(jiān)聽事件相關(guān)的初始化工作

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mActivity = (Activity) context;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        if (mContentView == null) {
            try {
                mContentView = inflater.inflate(getContentLayout(), container, false);
            } catch (Resources.NotFoundException e) {
                e.printStackTrace();
            }

            Preconditions.checkNotNull(mContentView, "根布局的id非法導(dǎo)致根布局為空,請(qǐng)檢查后重試!");

            unbinder = ButterKnife.bind(this, mContentView);
        }
        return mContentView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //視圖準(zhǔn)備完畢
        isViewReady = true;
        if (!isLazyLoad() || isFragmentVisible) {
            init();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        isFragmentVisible = isVisibleToUser;
        //如果視圖準(zhǔn)備完畢且Fragment處于可見狀態(tài),則開始初始化操作
        if (isLazyLoad() && isViewReady && isFragmentVisible) {
            init();
        }
    }

    public void init() {
        if (!isLoaded) {
            isLoaded = true;
            initView();
            initData();
            initEvent();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        //ButterKnife解綁
        if (unbinder != null) unbinder.unbind();
        isViewReady = false;
        isLoaded = false;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.destroy();
            mPresenter = null;
        }
    }

    @Override
    public void onSaveState(Bundle bundleToSave) {

    }

    @Override
    public void onRestoreState(Bundle bundleToRestore) {

    }

    @Override
    public boolean isUseEventBus() {
        return false;
    }
}

BaseFragment的作用如下:

  1. 延遲加載(懶加載)至会。 如果Fragment與ViewPager結(jié)合使用的話离咐,當(dāng)加載當(dāng)前Fragment時(shí),上一頁(yè)和下一頁(yè)的Fragment都會(huì)預(yù)先進(jìn)行加載奉件,這樣如果加載的內(nèi)容很多宵蛀,容易造成卡頓、速度慢县貌。
    延遲主要就是通過在setUserVisibleHint和onActivityCreated中做判斷來(lái)實(shí)現(xiàn)的术陶,當(dāng)視圖準(zhǔn)備完畢且Fragment處于可見狀態(tài)時(shí),才開始進(jìn)行初始化操作煤痕。重寫isLazyLoad()方法即可決定是否開啟懶加載功能梧宫。
    然后具體的fragment只需重寫getContentLayout()接谨、initView()、initData()塘匣、initEvent()中進(jìn)行相應(yīng)的操作即可脓豪。
    另外有一點(diǎn)需要注意,如果fragment并不是和Viewpager結(jié)合使用馆铁,而是通過FragmentManager的Transaction進(jìn)行add/hide/show的話跑揉,那么在顯示Fragment的時(shí)候锅睛,請(qǐng)顯式地調(diào)用setUserVisibleHint()埠巨,如下:
//包含多個(gè)Fragment的Activity中的代碼

//顯示或隱藏Fragment,用于切換Fragment的展示
private void addOrShowFragment(FragmentTransaction transaction, BaseFragment fragment, String tag) {
    if (mCurrentFragment == fragment) return;

    if (!fragment.isAdded()) {
        transaction.hide(mCurrentFragment).add(R.id.fl_movie, fragment, tag).commit();
    } else {
        transaction.hide(mCurrentFragment).show(fragment).commit();
    }

    //不與ViewPager嵌套的話现拒,需要顯式調(diào)用setUserVisibleHint
    mCurrentFragment.setUserVisibleHint(false);
    mCurrentFragment = fragment;
    mCurrentFragment.setUserVisibleHint(true);
}

  1. 銷毀Presenter層對(duì)View層的引用辣垒。
    這里涉及MVP開發(fā)模式,不了解的可以先點(diǎn)這里印蔬。由于Fragment經(jīng)常需要銷毀Presenter層對(duì)View層的引用勋桶,所以移至基類中實(shí)現(xiàn)。
  2. 實(shí)現(xiàn)IBaseFragment接口侥猬。
    實(shí)現(xiàn)該接口例驹,以便通過FragmentManager.FragmentLifecycleCallbacks完成部分"基類操作",看完2.2你就懂了退唠。

2.2 通過FragmentManager.FragmentLifecycleCallbacks實(shí)現(xiàn)

同樣顧名思義 --- Fragment生命周期回調(diào)鹃锈。
當(dāng)注冊(cè)了該回調(diào)用,每個(gè)Fragment進(jìn)入相關(guān)生命周期時(shí)都會(huì)觸發(fā)相關(guān)回調(diào)瞧预。
所以我們可以通過((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(callback, true)方法注冊(cè)回調(diào)屎债,然后在
FragmentLifecycleCallbacks里實(shí)現(xiàn)一些基類操作。
不多說垢油,直接上代碼盆驹。(代碼涉及了一些Dagger2,可以點(diǎn)這里了解)

@Singleton
public class FragmentLifeCallback extends FragmentManager.FragmentLifecycleCallbacks {

    @Inject
    SimpleArrayMap<String, IFragmentLife> mMapFragmentLife;
    @Inject
    Provider<IFragmentLife> mFragmentLifeProvider;

    @Inject
    public FragmentLifeCallback() {
    }

    @Override
    public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
        if (f instanceof IBaseFragment) {
            IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
            if (iFragmentLife == null || !iFragmentLife.isAdded()) {
                iFragmentLife = mFragmentLifeProvider.get();
                mMapFragmentLife.put(f.toString(), iFragmentLife);
//                RingLog.e("onCreate activity:" + activity.toString());
//                RingLog.e("onCreate iActivityLife:" + iActivityLife.toString());
            }
            iFragmentLife.onAttach(f, context);
        }
    }

    @Override
    public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onCreate(savedInstanceState);
        }
    }

    @Override
    public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onActivityCreate(savedInstanceState);
        }
    }

    @Override
    public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onCreateView(v,savedInstanceState);
        }
    }

    @Override
    public void onFragmentStarted(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onStart();
        }
    }

    @Override
    public void onFragmentResumed(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onResume();
        }
    }

    @Override
    public void onFragmentPaused(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onPause();
        }
    }

    @Override
    public void onFragmentStopped(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onStop();
        }
    }

    @Override
    public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onSaveInstanceState(outState);
        }
    }

    @Override
    public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onDestroyView();
        }
    }

    @Override
    public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onDestroy();
        }

        mMapFragmentLife.remove(f.toString());
    }

    @Override
    public void onFragmentDetached(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onDetach();
        }
    }
}

我把各生命周期具體要做的事情放到FragmentLife里執(zhí)行了滩愁,下面貼上FragmentLife的代碼:

public class FragmentLife implements IFragmentLife {

    private static final String SAVED_STATE = "saved_state";
    private final PublishSubject<FragmentEvent> mLifecycleSubject = PublishSubject.create();

    private Fragment mFragment;
    private View mContentView;
    private Bundle mSavedState;//用于保存/恢復(fù)數(shù)據(jù)

    @Override
    public void onAttach(Fragment fragment, Context context) {
        mFragment = fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        mLifecycleSubject.onNext(FragmentEvent.CREATE);
        if (((IBaseFragment) mFragment).isUseEventBus()) {
            DevRing.busManager().register(mFragment);
        }
    }

    @Override
    public void onCreateView(View view, Bundle savedInstanceState) {
        mLifecycleSubject.onNext(FragmentEvent.CREATE_VIEW);
        mContentView = view;
    }

    @Override
    public void onActivityCreate(Bundle savedInstanceState) {
        restoreStateFromArguments();
    }

    @Override
    public void onStart() {
        mLifecycleSubject.onNext(FragmentEvent.START);
    }

    @Override
    public void onResume() {
        mLifecycleSubject.onNext(FragmentEvent.RESUME);
    }

    @Override
    public void onPause() {
        mLifecycleSubject.onNext(FragmentEvent.PAUSE);
    }

    @Override
    public void onStop() {
        mLifecycleSubject.onNext(FragmentEvent.STOP);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        saveStateToArguments();
    }

    @Override
    public void onDestroyView() {
        mLifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW);

        if (mContentView != null) {
            ViewGroup parent = (ViewGroup) mContentView.getParent();
            if (parent != null) {
                parent.removeView(mContentView);
            }
        }

        saveStateToArguments();
    }

    @Override
    public void onDestroy() {
        mLifecycleSubject.onNext(FragmentEvent.DESTROY);

        if (((IBaseFragment) mFragment).isUseEventBus()) {
            DevRing.busManager().unregister(mFragment);
        }
        mContentView = null;
        mFragment = null;
    }

    @Override
    public void onDetach() {
        mLifecycleSubject.onNext(FragmentEvent.DETACH);
    }

    @Override
    public boolean isAdded() {
        return mFragment != null && mFragment.isAdded();
    }

    private void saveStateToArguments() {
        if (mFragment.getView() != null) {
            Bundle state = new Bundle();
            ((IBaseFragment) mFragment).onSaveState(state);
            mSavedState = state;
        }
        if (mSavedState != null) {
            Bundle b = mFragment.getArguments();
            if (b != null) {
                b.putBundle(SAVED_STATE, mSavedState);
            }
        }
    }

    private void restoreStateFromArguments() {
        Bundle b = mFragment.getArguments();
        if (b != null) {
            mSavedState = b.getBundle(SAVED_STATE);
            if (mSavedState != null) {
                ((IBaseFragment) mFragment).onRestoreState(mSavedState);
            }
        }
    }
}

接下來(lái)躯喇,只要你的Fragment實(shí)現(xiàn)了IBaseFragment接口(如果你的Activity實(shí)現(xiàn)了IBaseActivity,那還要確保isUseFragment()方法返回true)硝枉,即可通過FragmentLifecycleCallbacks實(shí)現(xiàn)以下“基類操作”:

  1. 幫助控制網(wǎng)絡(luò)請(qǐng)求的生命周期玖瘸。
    通過PublishSubject的操作,在onPause()/onStop()/onDestroy()中發(fā)射終止事件檀咙,以便控制Retrofit網(wǎng)絡(luò)請(qǐng)求在頁(yè)面進(jìn)入特定狀態(tài)時(shí)終止雅倒。
  2. EventBus的訂閱/解除訂閱
    根據(jù)isUseEventBus()來(lái)決定是否進(jìn)行EventBus的注冊(cè)/注銷弧可。
  3. 數(shù)據(jù)的保存與恢復(fù)
    fragment在保存和恢復(fù)數(shù)據(jù)方面蔑匣,要比Activity復(fù)雜些劣欢,具體可以看這篇文章http://blog.csdn.net/donglynn/article/details/47065999
    具體Fragment通過實(shí)現(xiàn)onSaveState(Bundle bundleToSave)進(jìn)行數(shù)據(jù)保存以及onRestoreState(Bundle bundleToRestore);進(jìn)行數(shù)據(jù)恢復(fù)即可裁良。

IBaseFragment接口代碼:

public interface IBaseFragment {
    /**
     * 需要保存數(shù)據(jù)時(shí)凿将,將數(shù)據(jù)寫進(jìn)bundleToSave
     */
    void onSaveState(Bundle bundleToSave);

    /**
     * 從bundleToRestore中獲取你保存金曲的數(shù)據(jù)
     */
    void onRestoreState(Bundle bundleToRestore);

    /**
     * 該Fragment是否訂閱事件總線
     * @return true則自動(dòng)進(jìn)行注冊(cè)/注銷操作,false則不注冊(cè)
     */
    boolean isUseEventBus();
}

3. Adapter基類

3.1 RecyclerBaseAdapter

public abstract class RecyclerBaseAdapter<T> extends RecyclerView.Adapter<ViewHolder> implements IRecyclerAdapter<T> {
    private static final String TAG = RecyclerBaseAdapter.class.getSimpleName();

    private List<T> mDataList;
    private Context mContext;

    protected RecyclerBaseAdapter(@NonNull Context context, @NonNull List<T> mDataList) {
        if (context == null) {
            throw new NullPointerException("context is not allow null!");
        }
        this.mDataList = mDataList;
        this.mContext = context;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        final int p = holder.getLayoutPosition();

        bindDataForView(holder, (mDataList != null && !mDataList.isEmpty()) ? (mDataList.size() > p ? mDataList.get(p) : null) : null, p);

    }

    @Override
    public int getItemCount() {
        return mDataList != null ? mDataList.size() : 0;
    }

    protected abstract void bindDataForView(ViewHolder holder, T t, int position);

    @Override
    public Context getContext() {
        return mContext;
    }

    @Override
    public T getItem(@IntRange(from = 0) int position) {
        if (position <= -1) {
            return null;
        }
        return !CollectionUtil.isEmpty(mDataList) ? mDataList.get(position) : null;
    }

    @Override
    public List<T> getDataList() {
        return mDataList;
    }

    //從某個(gè)位置開始价脾,插入一組數(shù)據(jù)
    @Override
    public void insertItems(@NonNull List<T> list, @IntRange(from = 0) int startIndex) {

        if (mDataList == null) {
            return;
        }

        if (list == null || list.isEmpty()) {
            LogUtil.e(TAG, "插入的數(shù)據(jù)集為空或長(zhǎng)度小于等于零, 請(qǐng)檢查你的數(shù)據(jù)集!");
            return;
        }

        if (this.mDataList.containsAll(list)) {
            return;
        }

        notifyItemRangeInserted(startIndex, list.size());
        mDataList.addAll(startIndex, list);
        notifyItemRangeChanged(startIndex, getItemCount() - startIndex);
    }

    //從最底下插入一組數(shù)據(jù)
    @Override
    public void insertItems(@NonNull List<T> list) {
        this.insertItems(list, mDataList.size());
    }

    //從某個(gè)位置開始牧抵,插入一個(gè)數(shù)據(jù)
    @Override
    public void insertItem(@NonNull T t, @IntRange(from = 0) int position) {

        if (mDataList == null) {
            return;
        }

        if (t == null) {
            LogUtil.e(TAG, "插入的數(shù)據(jù)為空, 請(qǐng)檢查你的數(shù)據(jù)!");
            return;
        }

        notifyItemInserted(position);
        mDataList.add(position, t);
        notifyItemRangeChanged(position, getItemCount() - position);
    }

    //從最底下插入一個(gè)數(shù)據(jù)
    @Override
    public void insertItem(@NonNull T t) {
        this.insertItem(t, mDataList.size());
    }

    //替換所有數(shù)據(jù)
    @Override
    public void replaceData(@NonNull List<T> list) {
        if (mDataList == null) {
            return;
        }

        if (list == null || list.isEmpty()) {
            LogUtil.e(TAG, "插入的數(shù)據(jù)集為空或長(zhǎng)度小于等于零, 請(qǐng)檢查你的數(shù)據(jù)集!");
            return;
        }

        mDataList = list;
        notifyDataSetChanged();
    }

    //從某個(gè)位置開始,更新n個(gè)數(shù)據(jù)
    @Override
    public void updateItems(@IntRange(from = 0) int positionStart, @IntRange(from = 0) int itemCount) {
        notifyItemRangeChanged(positionStart, itemCount);
    }

    //更新所有數(shù)據(jù)
    @Override
    public void updateAll() {
        updateItems(0, mDataList.size());
    }

    //移除某個(gè)位置的數(shù)據(jù)
    @Override
    public void removeItem(@IntRange(from = 0) int position) {
        if (CollectionUtil.isEmpty(mDataList) || position <= -1) {
            return;
        }
        notifyItemRemoved(position);
        mDataList.remove(position);
        notifyItemRangeChanged(position, getItemCount() - position);
    }

    //移除所有數(shù)據(jù)
    @Override
    public void removeAll() {
        if (CollectionUtil.isEmpty(mDataList)) {
            return;
        }

        notifyItemRangeRemoved(0, getItemCount());
        mDataList.clear();
        notifyItemRangeChanged(0, getItemCount());
    }
}

RecyclerBaseAdapter的作用如下:

  1. 重寫onBindViewHolder并提供抽象方法侨把。 由于列表項(xiàng)實(shí)體是不確定的犀变,所以用到了泛型。
    具體的Adapter繼承該基類秋柄,通過泛型傳入具體的實(shí)體類型获枝,然后重寫bindDataForView方法,即可更直接地得到實(shí)體數(shù)據(jù)骇笔。
  2. 插入省店、刪除、刷新列表項(xiàng)笨触。 提供相關(guān)方法懦傍,方便子類快速調(diào)用。

3.2 LoadMoreBaseAdapter

如果你的RecyclerView需要有上拉加載更多的功能(添加Footer)芦劣,那么可以繼承LoadMoreBaseAdapter粗俱。
它繼承RecyclerBaseAdapter,添加了Footer并提供了方法來(lái)設(shè)置footer的狀態(tài)持寄。

public abstract class LoadMoreBaseAdapter<T> extends RecyclerBaseAdapter<T> {

    // 普通布局
    private final int TYPE_ITEM = 1;
    // 腳布局
    private final int TYPE_FOOTER = 2;
    // 當(dāng)前加載狀態(tài)源梭,默認(rèn)為加載完成
    private int loadState = 2;
    // 正在加載
    public static final int LOADING = 1;
    // 加載完成
    public static final int LOADING_COMPLETE = 2;
    // 加載到底了(全部數(shù)據(jù)加載完畢)
    public static final int LOADING_END = 3;

    public LoadMoreBaseAdapter(@NonNull Context context, @NonNull List<T> mDataList) {
        super(context, mDataList);
    }

    @Override
    public int getItemCount() {
        return super.getItemCount() + 1;
    }

    @Override
    public int getItemViewType(int position) {
        // 最后一個(gè)item設(shè)置為FooterView
        if (position + 1 == getItemCount()) {
            return TYPE_FOOTER;
        } else {
            return TYPE_ITEM;
        }
    }


    @Override
    protected void bindDataForView(ViewHolder holder, T t, int position) {
        if (holder.getItemViewType() == TYPE_FOOTER) {
            ProgressBar pbLoading = holder.getView(R.id.pb_loading);
            TextView tvLoading = holder.getView(R.id.tv_loading);
            LinearLayout llEnd = holder.getView(R.id.ll_end);

            switch (loadState) {
                case LOADING: // 正在加載
                    pbLoading.setVisibility(View.VISIBLE);
                    tvLoading.setVisibility(View.VISIBLE);
                    llEnd.setVisibility(View.GONE);
                    break;

                case LOADING_COMPLETE: // 加載完成
                    pbLoading.setVisibility(View.INVISIBLE);
                    tvLoading.setVisibility(View.INVISIBLE);
                    llEnd.setVisibility(View.GONE);
                    break;

                case LOADING_END: // 加載到底
                    pbLoading.setVisibility(View.GONE);
                    tvLoading.setVisibility(View.GONE);
                    llEnd.setVisibility(View.VISIBLE);
                    break;

                default:
                    break;

            }
        } else {
            bindDataForView_(holder, t, position);
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //進(jìn)行判斷顯示類型,來(lái)創(chuàng)建返回不同的View
        if (viewType == TYPE_FOOTER) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_more_footer, parent, false);
            return new ViewHolder(view);
        } else {
            return onCreateViewHolder_(parent, viewType);
        }
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    // 如果當(dāng)前是footer的位置稍味,那么該item占據(jù)2個(gè)單元格废麻,正常情況下占據(jù)1個(gè)單元格
                    return getItemViewType(position) == TYPE_FOOTER ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    /**
     * 設(shè)置上拉加載狀態(tài)
     *
     * @param loadState 0.正在加載 1.加載完成 2.加載到底
     */
    public void setLoadState(int loadState) {
        this.loadState = loadState;
        notifyDataSetChanged();
    }

    protected abstract void bindDataForView_(ViewHolder holder, T t, int position);

    protected abstract ViewHolder onCreateViewHolder_(ViewGroup parent, int viewType);
}

當(dāng)然,完整的上拉加載更多的流程還要配合列表的滾動(dòng)監(jiān)聽來(lái)實(shí)現(xiàn)模庐。完整的流程代碼可以查看demo烛愧,效果圖


上拉加載更多

4. Presenter基類

不了解MVP模式的可以先看《安卓開發(fā)模式 --- MVP》

public abstract class BasePresenter<V extends IBaseView,M extends IBaseModel>{

    protected V mIView;
    protected M mIModel;

    public BasePresenter(V iView,M iModel) {
        mIView = iView;
        mIModel = iModel;
    }

    public BasePresenter(V iView) {
        mIView = iView;
    }

    public BasePresenter() {
    }

    /**
     * 釋放引用,防止內(nèi)存泄露掂碱,一般在activity和fragment銷毀時(shí)調(diào)用
     */
    public void destroy() {
        mIView = null;
    }
}

BasePresenter的作用:

  1. 提供mIView怜姿,mIModel方便子類調(diào)用。 由于IView疼燥,IModel的具體類型不確定沧卢,所以使用了泛型,子類通過泛型傳入具體的IView醉者、IModel類型但狭。
  2. 避免內(nèi)存泄漏披诗。 提供destroy()方法給V層銷毀時(shí)調(diào)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末立磁,一起剝皮案震驚了整個(gè)濱河市呈队,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唱歧,老刑警劉巖宪摧,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異颅崩,居然都是意外死亡几于,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門挨摸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)孩革,“玉大人岁歉,你說我怎么就攤上這事得运。” “怎么了锅移?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵熔掺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我非剃,道長(zhǎng)置逻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任备绽,我火速辦了婚禮券坞,結(jié)果婚禮上卫袒,老公的妹妹穿的比我還像新娘帮掉。我一直安慰自己,他們只是感情好瞳收,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布倍靡。 她就那樣靜靜地躺著猴伶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪塌西。 梳的紋絲不亂的頭發(fā)上他挎,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音捡需,去河邊找鬼办桨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛站辉,可吹牛的內(nèi)容都是我干的呢撞。 我是一名探鬼主播贸街,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼狸相!你這毒婦竟也來(lái)了薛匪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤脓鹃,失蹤者是張志新(化名)和其女友劉穎逸尖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘸右,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娇跟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了太颤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苞俘。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖龄章,靈堂內(nèi)的尸體忽然破棺而出吃谣,到底是詐尸還是另有隱情,我是刑警寧澤做裙,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布岗憋,位于F島的核電站,受9級(jí)特大地震影響锚贱,放射性物質(zhì)發(fā)生泄漏仔戈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一拧廊、第九天 我趴在偏房一處隱蔽的房頂上張望监徘。 院中可真熱鬧,春花似錦吧碾、人聲如沸凰盔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)廊蜒。三九已至,卻和暖如春溅漾,著一層夾襖步出監(jiān)牢的瞬間山叮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工添履, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屁倔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓暮胧,卻偏偏與公主長(zhǎng)得像锐借,于是被迫代替她去往敵國(guó)和親问麸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354