亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

當FragmentTransaction在add和replace時,它們之間的區別

2019-11-07 23:03:37
字體:
來源:轉載
供稿:網友

前言

我們在使用FragmentTransaction的時候,經常會遇到add,replace這兩個方法。 如下:

FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transition = fragmentManager.beginTransaction(); FragmentOne fragmentOne = new FragmentOne(); transition.add(R.id.container_layout,fragmentOne);// transition.replace(R.id.container_layout,fragmentOne); transition.commit();

在一般情況下,它們之間并沒有什么區別,都能達到一樣的效果。但是想想,如果真的沒有區別的話,Android就完全沒有必要同時提供這兩個方法了。 我們還是先來看看android中對這兩個方法的說明:

FragmentTransaction add (int containerViewId, Fragment fragment, String tag)

Add a fragment to the activity state. This fragment may optionally also have its view (if Fragment.onCreateView returns non-null) inserted into a container view of the activity. add是把一個fragment添加到activity中的容器container view中。

FragmentTransaction replace (int containerViewId, Fragment fragment, String tag)

Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here. repalce是先remove掉當前相同containerViewId 的所有fragment,然后在add當前這個fragment。

從上面的說明來看,這兩個的使用效果基本相同的。光從上面幾句話的表述中,也許并不能很好的解釋其中的原理。下面我還是從源碼的角度來進行說明。

源碼分析

FragmentManager是個抽象類,當我們執行getSupportFragmentManager方法時,得到的是它的實現類FragmentManagerImpl。FragmentTransaction同樣是抽象類,它的實現類是BackStackRecord類。從BackStackRecord中,我們可以看到add,replace方法。 add方法:

@Override public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) { doAddOp(containerViewId, fragment, tag, OP_ADD); return this; }

replace方法:

@Override public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) { if (containerViewId == 0) { throw new IllegalArgumentException("Must use non-zero containerViewId"); } doAddOp(containerViewId, fragment, tag, OP_REPLACE); return this; }

從上面可以看到,add和replace都是調用doAddOp方法,只是在最后的一個參數不同。

PRivate void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) { final Class fragmentClass = fragment.getClass(); final int modifiers = fragmentClass.getModifiers(); if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers) || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) { throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName() + " must be a public static class to be properly recreated from" + " instance state."); } fragment.mFragmentManager = mManager; if (tag != null) { if (fragment.mTag != null && !tag.equals(fragment.mTag)) { throw new IllegalStateException("Can't change tag of fragment " + fragment + ": was " + fragment.mTag + " now " + tag); } fragment.mTag = tag; } if (containerViewId != 0) { if (containerViewId == View.NO_ID) { throw new IllegalArgumentException("Can't add fragment " + fragment + " with tag " + tag + " to container view with no id"); } if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { throw new IllegalStateException("Can't change container ID of fragment " + fragment + ": was " + fragment.mFragmentId + " now " + containerViewId); } fragment.mContainerId = fragment.mFragmentId = containerViewId; } Op op = new Op(); op.cmd = opcmd; op.fragment = fragment; addOp(op); }

這個方法里面,首先判斷傳入的fragment方法是不是合法的。 接著,如果傳入的參數TAG不為空的話,將它賦值到fragment的mTag中,如:fragment.mTag = tag; 然后判斷containerViewId的合法后,執行賦值:fragment.mContainerId = fragment.mFragmentId = containerViewId; 最后將fragment加入到隊中,調用addOp方法。

void addOp(Op op) { if (mHead == null) { mHead = mTail = op; } else { op.prev = mTail; mTail.next = op; mTail = op; } op.enterAnim = mEnterAnim; op.exitAnim = mExitAnim; op.popEnterAnim = mPopEnterAnim; op.popExitAnim = mPopExitAnim; mNumOp++; }

以上完成了準備階段,上面貌似沒有解決add和replace之間的不同操作,我們繼續看BackStackRecord類,知道原來它繼承了Runable,run方法才是真正執行的方法。在while循環中的switch case包含了OP_ADD和OP_REPLACE的分支,這不正是剛才方法doAddOp中傳入的不同參數嗎。所以我們只需要關注這兩個case的分支執行的代碼就行了。

case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.addFragment(f, false); } break;case OP_REPLACE: { Fragment f = op.fragment; int containerId = f.mContainerId; if (mManager.mAdded != null) { for (int i = mManager.mAdded.size() - 1; i >= 0; i--) { Fragment old = mManager.mAdded.get(i); if (FragmentManagerImpl.DEBUG) Log.v(TAG, "OP_REPLACE: adding=" + f + " old=" + old); if (old.mContainerId == containerId) { if (old == f) { op.fragment = f = null; } else { if (op.removed == null) { op.removed = new ArrayList<Fragment>(); } op.removed.add(old); old.mNextAnim = exitAnim; if (mAddToBackStack) { old.mBackStackNesting += 1; if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " + old + " to " + old.mBackStackNesting); } mManager.removeFragment(old, transition, transitionStyle); } } } } if (f != null) { f.mNextAnim = enterAnim; mManager.addFragment(f, false); } } break;

其中OP_ADD很簡單,僅僅就是將fragment加入隊列中,我們來 看看OP_REPLACE。 這里面有個for循環,目的是將FragmentManagerImpl中,已經添加的Fragment全部遍歷出來,取出與當前fragment中mContainerId相同的fragment,并且remove掉,最后又重新調用addFragment,將它加入到隊列中來。這時調用的方法與OP_ADD相同。 在BackStackRecord中有FragmentManagerImpl引用,然后在構造器的參數列表中進行賦值初始化。在FragmentManagerImpl中的addFragment方法,用來保存每次add的Fragment,并將它放在mAdded的容器中。

public void addFragment(Fragment fragment, boolean moveToStateNow) { if (mAdded == null) { mAdded = new ArrayList<Fragment>(); } if (DEBUG) Log.v(TAG, "add: " + fragment); makeActive(fragment); if (!fragment.mDetached) { if (mAdded.contains(fragment)) { throw new IllegalStateException("Fragment already added: " + fragment); } mAdded.add(fragment); fragment.mAdded = true; fragment.mRemoving = false; if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } if (moveToStateNow) { moveToState(fragment); } } }

同樣與之對應的還有一個removeFragment的方法,用來處理remove Fragment。

public void removeFragment(Fragment fragment, int transition, int transitionStyle) { if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting); final boolean inactive = !fragment.isInBackStack(); if (!fragment.mDetached || inactive) { if (mAdded != null) { mAdded.remove(fragment); } if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } fragment.mAdded = false; fragment.mRemoving = true; moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED, transition, transitionStyle, false); } }

總結: 在一般的情況下使用add和replace,并沒有什么區別,replace會先查找FragmentManager中是否包含相同mContainerId 的fragment,如果有就先remove它,然后再add它。 注意它是根據containerViewId來進行比較的,并不是依據對象是否相等來判斷的。在這一點上還需要注意區別。


上一篇:Unity Shader中法線變換

下一篇:as筆記3

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
九九精品在线播放| 国产一区二区丝袜高跟鞋图片| 日韩精品亚洲元码| 亚洲成人a级网| 人妖精品videosex性欧美| 欧美精品18videos性欧美| 91久久综合亚洲鲁鲁五月天| 91精品国产高清自在线看超| 欧美一乱一性一交一视频| 国产精品爽爽爽| 欧美一区二区三区……| 91精品久久久久久综合乱菊| 亚洲性猛交xxxxwww| 正在播放欧美视频| 777国产偷窥盗摄精品视频| 亚洲精品久久久久久久久久久久久| 欧美在线视频免费播放| 中文字幕一区日韩电影| 日韩有码在线观看| 亚洲欧洲午夜一线一品| 久久精品亚洲94久久精品| 欧美在线影院在线视频| 欧洲成人在线观看| 国产69精品久久久久99| 国产精品第2页| 夜夜狂射影院欧美极品| 亚洲精品综合久久中文字幕| 欧美精品亚州精品| 国产一区二区三区在线播放免费观看| 国产日韩在线一区| 8090成年在线看片午夜| 久久精品国产一区二区三区| 亚洲第一精品福利| 久久免费视频这里只有精品| 91久久精品久久国产性色也91| 日韩精品丝袜在线| 欧美激情国产日韩精品一区18| 国产在线视频不卡| 国产精品久久色| 国产日韩精品综合网站| 亚洲自拍偷拍区| 欧美激情成人在线视频| 欧美激情视频在线观看| 中文字幕一区二区三区电影| 国产91在线播放九色快色| 日日狠狠久久偷偷四色综合免费| 成人免费在线视频网站| 久久精品99国产精品酒店日本| 国产成人精品国内自产拍免费看| 日韩欧美a级成人黄色| 亚洲精品在线看| 日韩精品在线免费播放| 精品久久香蕉国产线看观看gif| 欧美国产视频一区二区| 亚洲美女在线看| 欧美激情亚洲自拍| 欧美电影免费观看高清完整| 日韩电影大片中文字幕| 国产精品视频99| 日韩在线播放一区| 日韩在线视频二区| 国产成人精品一区二区三区| 国产日韩精品综合网站| 精品久久久久久中文字幕一区奶水| 日本成人黄色片| 欧美电影电视剧在线观看| 亚洲变态欧美另类捆绑| 欧美视频在线观看 亚洲欧| 国产精品高潮呻吟久久av无限| 福利精品视频在线| 国产91九色视频| 日韩av快播网址| 久久伊人免费视频| 中文字幕亚洲激情| 57pao精品| 亚洲va国产va天堂va久久| 91高潮在线观看| 国产精品久久久久久久久免费看| 在线视频日本亚洲性| 亚洲第一视频网站| 欧美成人黑人xx视频免费观看| 国产午夜精品理论片a级探花| 日韩欧美亚洲范冰冰与中字| 亚洲精品国产福利| 国产精品视频专区| 亚洲成人激情视频| 国产精品视频xxx| 亚洲精品福利资源站| 欧美在线免费看| 国产欧美一区二区三区久久人妖| 久久久精品国产| 色综合久久天天综线观看| 日韩欧美亚洲范冰冰与中字| 成人国产亚洲精品a区天堂华泰| 国语自产精品视频在线看| 国产成人精品久久二区二区| 国产精品免费视频xxxx| 国产成人精品一区二区在线| 国产一区二区日韩精品欧美精品| 久久综合久久88| 久久久精品一区二区三区| 97色在线视频观看| 懂色av一区二区三区| 欧美精品videossex88| 色婷婷av一区二区三区久久| 国产丝袜一区二区三区| 欧美黑人性视频| 国产精品成人观看视频国产奇米| 日韩av一区二区在线观看| 91精品国产高清久久久久久| 正在播放欧美视频| 国产成人极品视频| 成人午夜在线观看| 欧美激情xxxx性bbbb| 国产精品第10页| 91在线中文字幕| 欧美激情视频网站| 91久久精品久久国产性色也91| 国产精品美女主播在线观看纯欲| 久久久国产精品视频| 欧美精品久久久久久久免费观看| 亚洲成年网站在线观看| 美女久久久久久久| 亚洲自拍高清视频网站| 国产精品欧美风情| 国产综合在线看| 国产精品亚洲自拍| 亚洲女人天堂成人av在线| 91久久国产综合久久91精品网站| 久久亚洲精品一区| 亚洲欧美一区二区激情| 色综合五月天导航| 91丝袜美腿美女视频网站| 欧美另类99xxxxx| 欧美日韩一区免费| 欧美精品少妇videofree| 成人福利网站在线观看11| 欧美色道久久88综合亚洲精品| 国产精品成人国产乱一区| 国产成人精品免费视频| 精品亚洲一区二区三区在线播放| 欧美精品videossex性护士| 欧美高清性猛交| 亚洲午夜国产成人av电影男同| 日韩电影免费观看中文字幕| 91久久久久久久久久久久久| 国产91免费看片| 中国china体内裑精亚洲片| 91欧美精品成人综合在线观看| 久久久久久久久久国产精品| 亚洲欧美日韩一区在线| 成人自拍性视频| 成人在线视频网站| 国产精品午夜视频| 国产视频久久久久久久| 国产精品视频在线播放| 亚洲国产欧美一区二区三区同亚洲| 国产精品爽黄69| 中文字幕日韩电影| 亚洲成人a**站| 亚洲一区二区三区视频播放| 俺去了亚洲欧美日韩| 久久精品国产久精国产一老狼| 亚洲欧美日韩视频一区|