关键词:
作者:字节小站
1. 前言
Fragment真是一个非常老的家伙,它的第一条提交记录是在2010年,而最近的一条记录则是在2021年6月11号,足足11岁了,但是它却老当益壮,在Jetpack中大放异彩,Navigation组件就是基于Fragment的一个跳转组件,Google的单Activity项目结构就是一个Activity和多个Fragment项目结构。多年以来,一提到Fragment,大家脑海中的第一印象可能还停留在平板应用开发中了,它曾经在手机项目中高频使用Fragment的机会还真没那么多。一方面是因为手机项目一般都是多Activity结构实现的,不会涉及到那么多的Fragment使用,另一方面,Fragment也比Activity复杂,相比之下使用有点麻烦,甚至是痛苦,不好定位问题,所以在技术选型时,能避则避。它太难用了,以至于Square团队的Piwai大神(LeakCanary的作者)在2014年发表了一篇倡导反对使用Fragment的文章。不管怎么样,这么多年过去了,Android团队也一直没有放弃对Fragment的支持,甚至在Jetpack中,Fragment开始扮演越来越重要的角色了,最近关于Navigation的倡导使用越来越多了,加上我参与了一个平板项目,所以对Fragment主流程源码进行了一次全面的研究。收获颇多,相信将来对Navigation研究定是大有裨益。
2. 创建Fragment
根据官方文档,写一个简单的Demo。简单了解Fragment的使用。
2.1 新建一个Fragment类
class ExampleFragment extends Fragment
public ExampleFragment()
super(R.layout.example_fragment);
2.2 把Fragment添加到Activity上
把Fragment添加到Activity上可以通过xml文件和代码编程两种方式实现。本文只介绍第二种实现方式。
<!-- res/layout/example_activity.xml -->
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
public class ExampleActivity extends AppCompatActivity
public ExampleActivity()
super(R.layout.example_activity);
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.add(R.id.fragment_container_view, ExampleFragment.class, null)
.commit();
我们可以看到,主要是通过FragmentManager来将Fragment添加到fragment_container_view对应的布局中,Demo是蛮简单的,模板代码,网上拷贝一下就能用。但是FragmentManager、Transaction、commit()分别是什么意思,还有待深入探究一番。
3. 深入理解Fragment原理
3.1 Fragment本质是什么
3.1.1 Fragment本质是View
从前面的DEMO我们看到,Fragment会add到FragmentContainerView上面,能被添加到ViewGroup的组件,一定也是View或者ViewGroup。有源码为证:
//androidx.fragment.app.Fragment.java
ViewGroup mContainer;
// The View generated for this fragment.
View mView;
那么既然如此,何必大费周章呢,直接用View来替代Fragment不就好了,addView()、removeView()使用起来更简单直观。
当然了Fragment本质是View但是又不仅限于此, 在真实的项目中,界面往往很复杂,业务逻辑也很复杂,往往需要处理各种UI状态变化,比如:增加一组View,替换一组View,删除一组View,还需要和Activity协作。总之,如果让开发者自己去实现这一套逻辑,恐怕比使用Fragment要麻烦的多吧。尽管Fragment看起来蛮复杂的,但是还是远比我们自己去实现相同功能简单的多。
3.1.2 Fragment本质不仅限于View
Fragment作为一个View可以被添加到Activity的布局中去。但是他更强大,还有以下几个特性:
- 处理生命周期,比Activity生命周期还要复杂
- 通过FragmentTransaction操作多个Fragment
- 通过FragmentManager维护一个回退栈,回退到上一个FragmentTransaction操作的界面
//androidx.fragment.app.Fragment.java
static final int INITIALIZING = -1; // Not yet attached.
static final int ATTACHED = 0; // Attached to the host.
static final int CREATED = 1; // Created.
static final int VIEW_CREATED = 2; // View Created.
static final int AWAITING_EXIT_EFFECTS = 3; // Downward state, awaiting exit effects
static final int ACTIVITY_CREATED = 4; // Fully created, not started.
static final int STARTED = 5; // Created and started, not resumed.
static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
static final int RESUMED = 7; // Created started and resumed.
从代码我们可以看出,有8种状态。分为两类,View相关的以及和Activity状态相关的。后文会详细介绍,此处点到为止。
3.2 FragmentTransaction
3.2.1 FragmentTransaction概述
软件工程中有一门叫数据库的课程,数据库中有一个叫"事务"的概念,它表示多个操作是原子性的,要么一起成功,要么一起失败,典型的例子就是转账,张三给李四转账100元这么一个事务,存在两个操作,从张三的账户中扣除100元,给李四的账户增加100元。因为有了事务,不会存在只有某一个操作成功,而另一个操作失败的情况,否则后果不堪设想。
在Android中SharedPreference也有commit方法。
SharedPreferences sharedPreferences= getSharedPreferences("data",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("name", “Tom”);
editor.putInt("age", 28);
editor.putBoolean("marrid",false);
editor.commit();
上述功能,一次提交做了三件事情,putString,putInt,putBoolean。
而FragmentTransaction和SharedPreference类似。它可以同时操作多个Fragment。
假设有布局文件如下:
<LinearLayout android:orientation="vertical">
<ViewGroup1>
<Fragment1 />
</ViewGroup1>
<ViewGroup2>
<Fragment2 />
</ViewGroup2>
<ViewGroup3>
<Fragment3 />
</ViewGroup3>
</LinearLayout>
假设我们想在ViewGroup1上增加Fragment1,ViewGroup2上用Fragment2替换掉,把ViewGroup3上的Fragment移除掉。
伪代码如下:
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.add(ViewGroup1, Fragment1.class, null)
.replace(ViewGroup2,Fragment2.class,null)
.remove(Fragment3)
.commit();
问:这三个操作我为什么要放到一个事务中呢?我连续执行这三个操作不行吗?
答:有些场景下可以,有些场景下不可以。涉及到回退栈的时候,是否放到事务中,按返回键会有很大的区别。我们把上述三个操作分别命名为OP1、OP2、OP3。如果调用了FragmentTransaction.addToBackStack(),三个操作放到事务中时, 按返回键时会执行与OP1、OP2、OP3相反的操作,即ViewGroup1、ViewGroup2、ViewGroup3同时恢复到处理事务之前的状态。如果三个操作不放到事务中时, 则会依次恢复 ViewGroup3、ViewGroup2、ViewGroup1的状态
3.2.2 FragmentTransaction源码分析
3.2.2.1 支持的操作OP_CMD
//FragmentTransaction.java
static final int OP_NULL = 0;
static final int OP_ADD = 1;
static final int OP_REPLACE = 2;
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
static final int OP_DETACH = 6;
static final int OP_ATTACH = 7;
static final int OP_SET_PRIMARY_NAV = 8;
static final int OP_UNSET_PRIMARY_NAV = 9;
static final int OP_SET_MAX_LIFECYCLE = 10;
挑几个一眼就能看懂的。
- OP_ADD表示增加Fragment
- OP_REPLACE表示替换某个ViewGroup上的Fragment
- OP_REMOVE删除Fragment
- OP_HIDE隐藏Fragment,等同于View.setVisibility(View.GONE)
- OP_SHOW显示Fragment,等同于View.setVisibility(View.VISIBLE)
- OP_DETACH detach Fragment
- OP_ATTACH attach Fragment
对应的方法分别是:
//FragmentTransaction.java
public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)
doAddOp(0, fragment, tag, OP_ADD);
return this;
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment)
return replace(containerViewId, fragment, null);
public FragmentTransaction remove(@NonNull Fragment fragment)
addOp(new Op(OP_REMOVE, fragment));
return this;
3.2.2.2 OP类
public abstract class FragmentTransaction
ArrayList<Op> mOps = new ArrayList<>();
static final class Op
int mCmd;
Fragment mFragment;
int mEnterAnim;
int mExitAnim;
int mPopEnterAnim;
int mPopExitAnim;
Lifecycle.State mOldMaxState;
Lifecycle.State mCurrentMaxState;
Op()
Op(int cmd, Fragment fragment)
this.mCmd = cmd;
this.mFragment = fragment;
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
Op(int cmd, @NonNull Fragment fragment, Lifecycle.State state)
this.mCmd = cmd;
this.mFragment = fragment;
this.mOldMaxState = fragment.mMaxState;
this.mCurrentMaxState = state;
从源码中我们可以看到,FragmentTransaction中有ArrayList mOps。它表示一个事务中需要处理几个操作。而OP类最重要的两个字段就是mCmd和mFragment。表示对某个Fragment执行指定的操作。
3.2.2.3 FragmentTransaction.commit()方法
//FragmentTransaction.java
public abstract class FragmentTransaction
public abstract int commit();
我们看到commit()方法是个抽象方法。它由BackStackRecord类实现。
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, FragmentManager.OpGenerator
@Override
public int commit()
return commitInternal(false);
3.3 BackStackRecord
3.3.1 BackStackRecord概述
BackStackRecord是FragmentTransaction的子类,表示它支持同时操作多个Fragment。同时,顾名思义,它会被放到BackStack(回退栈)中。回退栈定义在FragmentManager中,是一个ArrayList集合。
//FragmentManager.java
ArrayList<BackStackRecord> mBackStack;
一言以蔽之,BackStackRecord支持事务操作,同时又会被放入到回退栈中
3.3.2 BackStackRecord commit流程
int commitInternal(boolean allowStateLoss)
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManager.isLoggingEnabled(Log.VERBOSE))
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", pw);
pw.close();
mCommitted = true;
if (mAddToBackStack)
mIndex = mManager.allocBackStackIndex();
else
mIndex = -1;
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
该方法最主要的就是调用了FragmentManager.enqueueAction方法
3.4 FragmentManager
3.4.1 FragmentManager概述
从前文,我们知道,对多个Fragment的操作会被记录到FragmentTransaction中,最终调用FragmentManager.enqueueAction方法,真正执行Fragment操作。
3.4.2 操作调用流程
1. FragmentManager.enqueueAction()
void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss)
if (!allowStateLoss)
if (mHost == null)
if (mDestroyed)
throw new IllegalStateException("FragmentManager has been destroyed");
else
throw new IllegalStateException("FragmentManager has not been attached to a "
+ "host.");
checkStateLoss();
synchronized (mPendingActions)
if (mHost == null)
if (allowStateLoss)
// This FragmentManager isn't attached, so drop the entire transaction.
return;
throw new IllegalStateException("Activity has been destroyed");
mPendingActions.add(action);
scheduleCommit();
该方法最终调用到scheduleCommit()方法
2. FragmentManager.scheduleCommit()
void scheduleCommit()
synchronized (mPendingActions)
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions.size() == 1;
if (postponeReady || pendingReady)
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
updateOnBackPressedCallbackEnabled();
该方法最终通过Handler执行mExecCommit
3. FragmentManager.mExecCommit
private Runnable mExecCommit = new Runnable()
@Override
public void run()
execPendingActions(true);
;
该方法最终调用execPendingActions
4. FragmentManager.execPendingActions()
boolean execPendingActions(boolean allowStateLoss)
ensureExecReady(allowStateLoss);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop))
mExecutingActions = true;
try
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
finally
cleanupExec();
didSomething = true;
updateOnBackPressedCallbackEnabled();
doPendingDeferredStart();
mFragmentStore.burpActive();
return didSomething;
重点关注removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop)
5. FragmentManager.removeRedundantOperationsAndExecute()
private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop)
方法比较长省略代码,最终调用executeOpsTogether
6. FragmentManager.executeOpsTogether
private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex)
方法比较长省略代码,最终调用executeOps方法
7. FragmentManager.executeOps()
private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex)
for (int i = startIndex; i < endIndex; i++)
final BackStackRecord record = records.get(i);
final boolean isPop = isRecordPop.get(i);
if (isPop)
record.bumpBackStackNesting(-1);
// Only execute the add operations at the end of
// all transactions.
boolean moveToState = i == (endIndex - 1);
record.executePopOps(moveToState);
else
record.bumpBackStackNesting(1);
record.executeOps();
该方法分为两种情况,入栈和出栈,对应commit()和FragmentManager.popBackStack()操作。
8. FragmentManager.executeOps()
void executeOps()
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++)
final Op op = mOps.get(opNum);
final Fragment f = op.mFragment;
if (f != null)
f.setPopDirection(false);
f.setNextTransition(mTransition);
f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames);
switch (op.mCmd)
case OP_ADD:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.addFragment(f);
break;
case OP_REMOVE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.removeFragment(f);
break;
case OP_HIDE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.hideFragment(f);
break;
case OP_SHOW:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.showFragment(f);
break;
case OP_DETACH:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.detachFragment(f);
break;
case OP_ATTACH:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.attachFragment(f);
break;
case OP_SET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(f);
break;
case OP_UNSET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(null);
break;
case OP_SET_MAX_LIFECYCLE:
mManager.setMaxLifecycle(f, op.mCurrentMaxState);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null)
if (!FragmentManager.USE_STATE_MANAGER)
mManager.moveFragmentToExpectedState(f);
if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER)
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
该方法做了两件事,其一:根据OP.mCmd,操作FragmentManager对应的方法,该步骤并不会真正执行操作,也只是做记录操作,其二:调用mManager.moveToState(mManager.mCurState, true)
最终会调用到mManager.moveToState(Fragment f, int newState)方法,它是Fragment框架中真正核心方法
3.5 FragmentManager的核心方法void moveToState(Fragment f, int newState)
作为核心方法,并没有放在3.4章节中,只是为了突出它的核心地位。
void moveToState(@NonNull Fragment f, int newState)
FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
if (fragmentStateManager == null)
// Ideally, we only call moveToState() on active Fragments. However,
// in restoreSaveState() we can call moveToState() on retained Fragments
// just to clean them up without them ever being added to mActive.
// For these cases, a brand new FragmentStateManager is enough.
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
mFragmentStore, f);
// Only allow this FragmentStateManager to go up to CREATED at the most
fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
// When inflating an Activity view with a resource instead of using setContentView(), and
// that resource adds a fragment using the <fragment> tag (i.e. from layout and in layout),
// the fragment will move to the VIEW_CREATED state before the fragment manager
// moves to CREATED. So when moving the fragment manager moves to CREATED and the
// inflated fragment is already in VIEW_CREATED we need to move new state up from CREATED
// to VIEW_CREATED. This avoids accidentally moving the fragment back down to CREATED
// which would immediately destroy the Fragment's view. We rely on computeExpectedState()
// to pull the state back down if needed.
if (f.mFromLayout && f.mInLayout && f.mState == Fragment.VIEW_CREATED)
newState = Math.max(newState, Fragment.VIEW_CREATED);
newState = Math.min(newState, fragmentStateManager.computeExpectedState());
if (f.mState <= newState)
// If we are moving to the same state, we do not need to give up on the animation.
if (f.mState < newState && !mExitAnimationCancellationSignals.isEmpty())
// The fragment is currently being animated... but! Now we
// want to move our state back up. Give up on waiting for the
// animation and proceed from where we are.
cancelExitAnimation(f);
switch (f.mState)
case Fragment.INITIALIZING:
if (newState > Fragment.INITIALIZING)
fragmentStateManager.attach();
// fall through
case Fragment.ATTACHED:
if (newState > Fragment.ATTACHED)
fragmentStateManager.create();
// fall through
case Fragment.CREATED:
// We want to unconditionally run this anytime we do a moveToState that
// moves the Fragment above INITIALIZING, including cases such as when
// we move from CREATED => CREATED as part of the case fall through above.
if (newState > Fragment.INITIALIZING)
fragmentStateManager.ensureInflatedView();
if (newState > Fragment.CREATED)
fragmentStateManager.createView();
// fall through
case Fragment.VIEW_CREATED:
if (newState > Fragment.VIEW_CREATED)
fragmentStateManager.activityCreated();
// fall through
case Fragment.ACTIVITY_CREATED:
if (newState > Fragment.ACTIVITY_CREATED)
fragmentStateManager.start();
// fall through
case Fragment.STARTED:
if (newState > Fragment.STARTED)
fragmentStateManager.resume();
else if (f.mState > newState)
switch (f.mState)
case Fragment.RESUMED:
if (newState < Fragment.RESUMED)
fragmentStateManager.pause();
// fall through
case Fragment.STARTED:
if (newState < Fragment.STARTED)
fragmentStateManager.stop();
// fall through
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED)
if (isLoggingEnabled(Log.DEBUG))
Log.d(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null)
// Need to save the current view state if not
// done already.
if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null)
fragmentStateManager.saveViewState();
// fall through
case Fragment.VIEW_CREATED:
if (newState < Fragment.VIEW_CREATED)
FragmentAnim.AnimationOrAnimator anim = null;
if (f.mView != null && f.mContainer != null)
// Stop any current animations:
f.mContainer.endViewTransition(f.mView);
f.mView.clearAnimation();
// If parent is being removed, no need to handle child animations.
if (!f.isRemovingParent())
if (mCurState > Fragment.INITIALIZING && !mDestroyed
&& f.mView.getVisibility() == View.VISIBLE
&& f.mPostponedAlpha >= 0)
anim = FragmentAnim.loadAnimation(mHost.getContext(),
f, false, f.getPopDirection());
f.mPostponedAlpha = 0;
// Robolectric tests do not post the animation like a real device
// so we should keep up with the container and view in case the
// fragment view is destroyed before we can remove it.
ViewGroup container = f.mContainer;
View view = f.mView;
if (anim != null)
FragmentAnim.animateRemoveFragment(f, anim,
mFragmentTransitionCallback);
container.removeView(view);
if (FragmentManager.isLoggingEnabled(Log.VERBOSE))
Log.v(FragmentManager.TAG, "Removing view " + view + " for "
+ "fragment " + f + " from container " + container);
// If the local container is different from the fragment
// container, that means onAnimationEnd was called, onDestroyView
// was dispatched and the fragment was already moved to state, so
// we should early return here instead of attempting to move to
// state again.
if (container != f.mContainer)
return;
// If a fragment has an exit animation (or transition), do not destroy
// its view immediately and set the state after animating
if (mExitAnimationCancellationSignals.get(f) == null)
fragmentStateManager.destroyFragmentView();
// fall through
case Fragment.CREATED:
if (newState < Fragment.CREATED)
if (mExitAnimationCancellationSignals.get(f) != null)
// We are waiting for the fragment's view to finish animating away.
newState = Fragment.CREATED;
else
fragmentStateManager.destroy();
// fall through
case Fragment.ATTACHED:
if (newState < Fragment.ATTACHED)
fragmentStateManager.detach();
if (f.mState != newState)
if (isLoggingEnabled(Log.DEBUG))
Log.d(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+ "expected state " + newState + " found " + f.mState);
f.mState = newState;
该方法是整个Fragment框架中的核心方法,它会根据目标state和Fragment当前的state一步一步的升级或降级Fragment的State。最终回调到Fragment的相关生命周期方法。 至此整个commit方法的调用链条就分析完毕了。
由于篇幅有限,mManager.moveToState(Fragment f, int newState)我将新写一篇文章,专门图解一番。其实LifeCycle组件的State变化也是类似的,一步一步升级或降级。
最后
小编分享一些 Android 开发相关的学习文档、面试题、Android 核心笔记等等文档,希望能帮助到大家学习提升,如有需要参考的可以直接去我 CodeChina地址:https://codechina.csdn.net/u012165769/Android-T3 访问查阅。
jetpack之navigation(代码片段)
navigation基本用法如下定义基础跳转fragmentNavHostFragment在首页的layout中如我的首页是homefragment<fragmentandroid:id="@+id/my_nav_host_fragment"android:name="androidx.navigation.fragment.NavHo 查看详情
androidjetpack之navigation(代码片段)
...选择自动帮你添加依赖,否则使用不了1.2.添加NavHostFragmentNavHostFragment是一个特殊的Fragment,我们需要将其添加到Activity的布局文件中,作为其他Fragment的容器。这里我们直接修改mainactivity中的布局文件,添加:&... 查看详情
android:安卓学习笔记之navigation的简单理解和使用(代码片段)
...概念1.1、背景1.2、含义2、组成2.1、Navigationgraph2.2、NavHostFragment2.3、NavController3、基本使用3.1、引入依赖3.2、创建导航视图3.3、配置graph:添加fragment3.4、添加NavHostFragment3.5、通过NavController管理fragment之间的跳转3.5.1、NavController... 查看详情
Android 崩溃 onCreate() - Fragment 无法转换为 androidx.navigation.fragment.NavHostFragment
】Android崩溃onCreate()-Fragment无法转换为androidx.navigation.fragment.NavHostFragment【英文标题】:AndroidcrashonCreate()-Fragmentcannotbecasttoandroidx.navigation.fragment.NavHostFragment【发布时间】:2020-12-2901:17:45【问题描述】:我决定为我的应用执行Fire 查看详情
navigation+bottomnavigationview实现的tab效果重建fragment问题
Navigation+BottomNavigationView实现的tab效果重建fragment问题由于这个控件内部实现会导致fragment频繁重建。因此我们需要对它的listener做一点定制,来处理这个问题valperiodManagerFragment:Fragment=PeriodManagerFragment()valmineFragment:Fragm 查看详情
面试官:我们来聊聊fragment和activity
一丶Fragment1、谈一谈Fragment的生命周期?参考回答:Fragment从创建到销毁整个生命周期中涉及到的方法依次为:onAttach()→onCreate()→onCreateView()→onActivityCreated()→onStart()→onResume()→onPause()→onStop()→onDestroyView()→o 查看详情
官方架构组件navigation管理fragment框架(代码片段)
...构组件Navigation让单Activity应用成为首选架构,更好的管理Fragment框架Navigation目前仅AndroidStudio3.2以上版本支持,如果您的版本不足3.2,下载AndroidStudio3.2以上版本。快速开发组件可单独使用,也可以同时工作,当使用kotlin语言特性... 查看详情
android:单activity多fragment,navigation实现fragment跳转,fragment之间通过viewmodel共享数据(代码片段)
单Activity多Fragment,Navigation实现Fragment跳转,Fragment之间通过ViewModel共享数据1、MainActivity2、HomeFragment,DetailFragment2.1、HomeFragment2.2、DetailFragment3、MyViewModel参考1、MainActivity1、activity_ma 查看详情
Navigation popBackStack 禁用进一步导航到此 Fragment
】NavigationpopBackStack禁用进一步导航到此Fragment【英文标题】:NavigationpopBackStackdisablesfurthernavigationtothisFragment【发布时间】:2020-02-0902:09:57【问题描述】:我在将Navigation组件与此代码一起使用时加载了一个片段,它可以工作。find... 查看详情
navigation+bottomnavigationview实现的tab效果重建fragment问题(代码片段)
Navigation+BottomNavigationView实现的tab效果重建fragment问题由于这个控件内部实现会导致fragment频繁重建。因此我们需要对它的listener做一点定制,来处理这个问题valperiodManagerFragment:Fragment=PeriodManagerFragment()valmineFragment:Fragm 查看详情
navigation+bottomnavigationview实现的tab效果重建fragment问题(代码片段)
Navigation+BottomNavigationView实现的tab效果重建fragment问题由于这个控件内部实现会导致fragment频繁重建。因此我们需要对它的listener做一点定制,来处理这个问题valperiodManagerFragment:Fragment=PeriodManagerFragment()valmineFragment:Fragm 查看详情
如何在 JetPack Navigation 组件中托管 Fragment 的 Activity 中调用导航 Fragments 函数?
】如何在JetPackNavigation组件中托管Fragment的Activity中调用导航Fragments函数?【英文标题】:HowcanIcallanavigatedFragment\'sfunctionintheActivityhostingthefragmentviaJetPack\'sNavigationcomponent?【发布时间】:2020-04-0407:36:18【问题描述】:我从FragmentManag... 查看详情
Navigation Components popBackStack() 是不是保留 Fragment 状态?
】NavigationComponentspopBackStack()是不是保留Fragment状态?【英文标题】:DoesNavigationComponentspopBackStack()retainsFragmentstate?NavigationComponentspopBackStack()是否保留Fragment状态?【发布时间】:2019-12-0123:09:16【问题描述】:当我使用新的导航组... 查看详情
navigation+bottomnavigationview实现的tab效果重建fragment问题(代码片段)
Navigation+BottomNavigationView实现的tab效果重建fragment问题由于这个控件内部实现会导致fragment频繁重建。因此我们需要对它的listener做一点定制,来处理这个问题valperiodManagerFragment:Fragment=PeriodManagerFragment()valmineFragment:Fragment&... 查看详情
navigation+bottomnavigationview实现的tab效果重建fragment问题(代码片段)
Navigation+BottomNavigationView实现的tab效果重建fragment问题由于这个控件内部实现会导致fragment频繁重建。因此我们需要对它的listener做一点定制,来处理这个问题valperiodManagerFragment:Fragment=PeriodManagerFragment()valmineFragment:Fragment&... 查看详情
bom之navigator对象和用户代理检测
...avigator对象是所有支持javascript的浏览器所共有的。本文将详细介绍navigator对象和用户代理检测 属性 与其他BOM对象的情况一样,每个浏览器中的navigator对象也都有一套自己的属性。下表列出了存在于所有浏览器中的属性和... 查看详情
将 MapActivity (FragmentActivity) 添加到 Navigation Drawers (Fragment)
】将MapActivity(FragmentActivity)添加到NavigationDrawers(Fragment)【英文标题】:addingaMapActivity(FragmentActivity)toNavigationDrawers(Fragment)【发布时间】:2020-12-1202:12:50【问题描述】:我正在尝试在AndroidStudio中学习编码,但在活动方面遇到了问题... 查看详情
android:安卓学习笔记之navigation的简单理解和使用(代码片段)
...概念1.1、背景1.2、含义2、组成2.1、Navigationgraph2.2、NavHostFragment2.3、NavController3、基本使用3.1、引入依赖3.2、创建导航视图3.3、配置graph:添加fragment3.4、添加NavHostFragment3.5、通过NavController管理fra 查看详情