Android 多Fragment切換優(yōu)化

問題分析


一直在簡書里看別人的技術(shù)貼,今天我也來寫點自己的心得!最近在寫一個項目用到大量的Fragment后的總結(jié)!

我想剛剛接觸安卓的同學(xué)或許會這么寫:

FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.add(ViewId,fragment);// 或者fragmentTransaction.replace(ViewId,fragment);
fragmentTransaction.commit();

基礎(chǔ)更好一點的同學(xué)會用show和hide方法

FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.hide(new FirstFragment())
        .show(new SecondFragment())
        .commit();

誠然這兩種都可以切換Fragment,但是面對用戶大量點擊來回切換,或者你的Fragment本來就很多,每次都這樣操作,那么很快你的應(yīng)用就會OOM,就算不崩那也會異常的卡頓!so why?

當我們replace時發(fā)生了以下的生命周期:

image

想想看每次都replace一下??!這世界會有多美好!?。∧敲磫栴}出在哪?回過頭看看代碼就會發(fā)現(xiàn)每次在add/replace或者show/hide都會new 一個新的實例,這就是致命原因?。。。。?/p>

廢話不多說,亮出我的方法(抽取后的):

 /**
 *  Fragment的添加
 * @param manager Fragment管理器
 * @param aClass 相應(yīng)的Fragment對象的getClass
 * @param containerId 容器的id
 * @param args 需要傳值的話可將bundle填入  不需要傳值就填null
 */
protected void addFragment(FragmentManager manager, Class<? extends BaseFragment> aClass, int containerId, Bundle args) {

    String tag = aClass.getName();

    Logger.d("%s add fragment %s", TAG, aClass.getSimpleName());

    Fragment fragment = manager.findFragmentByTag(tag);

    FragmentTransaction transaction = manager.beginTransaction(); // 開啟一個事務(wù)

    if (fragment == null) {// 沒有添加
        try {
            fragment = aClass.newInstance(); // 通過反射 new 出一個 fragment 的實例

            BaseFragment baseFragment = (BaseFragment) fragment; // 強轉(zhuǎn)成我們base fragment

            // 設(shè)置 fragment 進入,退出, 彈進,彈出的動畫
            transaction.setCustomAnimations(baseFragment.enter(), baseFragment.exit(), baseFragment.popEnter(), baseFragment.popExit());

            transaction.add(containerId, fragment, tag);

            if (baseFragment.isNeedToAddBackStack()) { // 判斷是否需要加入回退棧
                transaction.addToBackStack(tag); // 加入回退棧時制定一個tag,以便在找到指定的事務(wù)
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        if (fragment.isAdded()) {
            if (fragment.isHidden()) {
                transaction.show(fragment);
            }
        } else {
            transaction.add(containerId, fragment, tag);
        }
    }

    if (fragment != null) {
        fragment.setArguments(args);
        hideBeforeFragment(manager, transaction, fragment);
        transaction.commit();
    }
}


/**
 * 除當前 fragment 以外的所有 fragment 進行隱藏
 *
 * @param manager
 * @param transaction
 * @param currentFragment
 */
private void hideBeforeFragment(FragmentManager manager, FragmentTransaction transaction, Fragment currentFragment) {

    List<Fragment> fragments = manager.getFragments();

    for (Fragment fragment : fragments) {
        if (fragment != currentFragment && !fragment.isHidden()) {
            transaction.hide(fragment);
        }
    }
}

略微解釋一下:

先查詢fragmentManager 所在的activitiy 中是否已經(jīng)添加了這個fragment
第一步 先從一個mAdded 的一個ArrayList遍歷查找,如果找不到再從 一個 叫 mActive 的 SparseArray的一個map里面查找。

注意:

1.一個 fragment 被 remove 掉后,只會從 mAdded 里面刪除,不會從 mActive 里面刪除,只有當這個fragment 所在的 transaction 從回退棧里面移除后才會 從mActive 刪除

  1. 當我們add 一個fragment時 會把我們的fragment 添加到 mAdded 里面,不會添加到 mActive。
  2. 只有當我們把 transaction 添加到回退棧的時候,才會把我們的 fragment 添加到 mActive 里面。所以我們通過 findFragmentByTag 方法查找出來的 fragment 不一定是被添加到我們的 activity 中。

使用:

代碼比較多,但是我個人感覺使用起來比較方便,而且功能也比較完善,使用的時候只需要兩行代碼:

HomeFragment1 homeFragment = new HomeFragment1();
addFragment(getSupportFragmentManager(),homeFragment.getClass(),R.id.main_body,null);

當我們需要傳值的時候,只需要將準備好的bundle以參數(shù)的形式填入即可。

我還增加了一個是否加入回退棧的判斷,用于實現(xiàn)一些有關(guān)回退棧的需求,實現(xiàn)這個功能還需要在BaseFragment中定義一個方法:

protected boolean isNeedToAddBackStack() {
        return true;
}

也就這么點內(nèi)容,各位大佬如果看出什么問題或者有什么更好的方法,歡迎大家在下方評論留言

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 有一段時間沒有寫博客了,作為2017年的第一篇,初衷起始于前段時間一個接觸安卓開發(fā)還不算太長時間的朋友聊到的一個問...
    Machivellia閱讀 4,308評論 0 44
  • Fragment是什么? Fragment是Android3.0后引入的一個新的API,他出現(xiàn)的初衷是為了適應(yīng)大屏...
    luoqiang108閱讀 459評論 0 1
  • 《Android Fragment完全解析,關(guān)于碎片你所需知道的一切》 我們都知道,Android上的界面展示都是...
    cxm11閱讀 2,349評論 2 19
  • Fragment的應(yīng)用真的是越來越廣泛了,之前Android在3.0版本加入Fragment的時候,主要是為了解決...
    閑庭閱讀 3,236評論 0 10
  • 目錄 起源 android 3.0(api11)引入了fragment(碎片)這個概念,起初主要是為了給大屏幕(如...
    不愛牧羊的牧羊犬閱讀 1,294評論 1 2

友情鏈接更多精彩內(nèi)容