首页 > 其他分享 >Fragment原理解析androidx版本&ViewPager与Fragment

Fragment原理解析androidx版本&ViewPager与Fragment

时间:2023-06-02 21:32:30浏览次数:62  
标签:java androidx Fragment ViewPager StackTraceElement fragment final op


资料

Fragment生命周期为什么要通过Fragment.setArguments(Bundle)传递参数

单独


问题:
动态方式,静态方式添加

  1. 随Activity启动
  2. 动态添加
  3. 回退栈
  4. onSaveInstance

静态方式添加Fragment

mHost 是这个
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
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 st加粗样式arted.
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.

Activity和Fragment的生命周期

Activity -> onCreate*
Fragment -> onAttach
Fragment -> onCreate

Activity -> onStart*
Fragment -> onCreateView
Fragment -> onViewCreated
Fragment -> onStart

Activity -> onResume*
Fragment -> onResume

Activity -> onPause*
Fragment -> onPause

Activity -> onStop*
Fragment -> onStop

Activity -> onDestroy*
Fragment -> onDestroyView
Fragment -> onDestroy
Fragment -> onDetach
0 = {StackTraceElement@21058} "dalvik.system.VMStack.getThreadStackTrace(Native Method)"
1 = {StackTraceElement@21059} "java.lang.Thread.getStackTrace(Thread.java:1724)"
2 = {StackTraceElement@21060} "java.lang.Thread.getAllStackTraces(Thread.java:1800)"
3 = {StackTraceElement@21061} "androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)"
4 = {StackTraceElement@21062} "androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2196)"
5 = {StackTraceElement@21063} "androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)"
6 = {StackTraceElement@21064} "androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1971)"
7 = {StackTraceElement@21065} "androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:311)"
8 = {StackTraceElement@21066} "androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:180)"
9 = {StackTraceElement@21067} "androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:52)"
10 = {StackTraceElement@21068} "androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)"
11 = {StackTraceElement@21069} "androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)"
12 = {StackTraceElement@21070} "androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)"
13 = {StackTraceElement@21071} "android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1073)"
14 = {StackTraceElement@21072} "android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1001)"
15 = {StackTraceElement@21073} "android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)"
16 = {StackTraceElement@21074} "android.view.LayoutInflater.rInflate(LayoutInflater.java:1127)"
17 = {StackTraceElement@21075} "android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)"
18 = {StackTraceElement@21076} "android.view.LayoutInflater.inflate(LayoutInflater.java:686)"
19 = {StackTraceElement@21077} "android.view.LayoutInflater.inflate(LayoutInflater.java:538)"
20 = {StackTraceElement@21078} "android.view.LayoutInflater.inflate(LayoutInflater.java:485)"
21 = {StackTraceElement@21079} "androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:706)"
22 = {StackTraceElement@21080} "androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195)"
23 = {StackTraceElement@21081} "com.joyy.android_project.MainActivity.onCreate(MainActivity.kt:21)"
24 = {StackTraceElement@21082} "android.app.Activity.performCreate(Activity.java:8051)"
25 = {StackTraceElement@21083} "android.app.Activity.performCreate(Activity.java:8031)"
26 = {StackTraceElement@21084} "android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)"
27 = {StackTraceElement@21085} "android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)"
28 = {StackTraceElement@21086} "android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)"
29 = {StackTraceElement@21087} "android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)"
30 = {StackTraceElement@21088} "android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)"
31 = {StackTraceElement@21089} "android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)"
32 = {StackTraceElement@21090} "android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)"
33 = {StackTraceElement@21091} "android.os.Handler.dispatchMessage(Handler.java:106)"
34 = {StackTraceElement@21092} "android.os.Looper.loopOnce(Looper.java:201)"
35 = {StackTraceElement@21093} "android.os.Looper.loop(Looper.java:288)"
36 = {StackTraceElement@21094} "android.app.ActivityThread.main(ActivityThread.java:7839)"
37 = {StackTraceElement@21095} "java.lang.reflect.Method.invoke(Native Method)"
38 = {StackTraceElement@21096} "com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)"
39 = {StackTraceElement@21097} "com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)"

静态方式#创建FragmentContainerView的时候启动事物

FragmentContainerView(@NonNull Context context, @NonNull AttributeSet attrs, @NonNull FragmentManager fm) {
    super(context, attrs);
    String name = attrs.getClassAttribute();
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FragmentContainerView);
    if (name == null) {
        name = a.getString(R.styleable.FragmentContainerView_android_name);
    }
    String tag = a.getString(R.styleable.FragmentContainerView_android_tag);
    a.recycle();
    int id = getId();
    Fragment existingFragment = fm.findFragmentById(id);
    // If there is a name and there is no existing fragment,
    // we should add an inflated Fragment to the view.
    if (name != null && existingFragment == null) {
        if (id <= 0) {
            final String tagMessage = tag != null
                    ? " with tag " + tag
                    : "";
            throw new IllegalStateException("FragmentContainerView must have an android:id to "
                    + "add Fragment " + name + tagMessage);
        }
        Fragment containerFragment = fm.getFragmentFactory().instantiate(context.getClassLoader(), name);
        containerFragment.onInflate(context, attrs, null);
        fm.beginTransaction()
                .setReorderingAllowed(true)
                .add(this, containerFragment, tag)
                .commitNowAllowingStateLoss();
    }
    fm.onContainerAvailable(this);

在构造函数中commit

fm.beginTransaction()
                    .setReorderingAllowed(true)
                    .add(this, containerFragment, tag)
                    .commitNowAllowingStateLoss();

FragmentManager是设置LayoutInflater.setFactory2()

addFragment的时候,就保存在FragmentStore中

FragmentStateManager addFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
        FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
        fragment.mFragmentManager = this;
        mFragmentStore.makeActive(fragmentStateManager);
        if (!fragment.mDetached) {
            mFragmentStore.addFragment(fragment);
            fragment.mRemoving = false;
            if (fragment.mView == null) {
                fragment.mHiddenChanged = false;
            }
            if (isMenuAvailable(fragment)) {
                mNeedMenuInvalidate = true;
            }
        }
        return fragmentStateManager;
    }

    void makeActive(@NonNull FragmentStateManager newlyActive) {
        Fragment f = newlyActive.getFragment();
        if (containsActiveFragment(f.mWho)) {
            return;
        }
        mActive.put(f.mWho, newlyActive);
        if (f.mRetainInstanceChangedWhileDetached) {
            if (f.mRetainInstance) {
                mNonConfig.addRetainedFragment(f);
            } else {
                mNonConfig.removeRetainedFragment(f);
            }
            f.mRetainInstanceChangedWhileDetached = false;
        }
        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
            Log.v(TAG, "Added fragment to active set " + f);
        }
    }

总结:

  1. FragmentContainerView在Layout的时候有一个添加事物的操作
  2. 重写了setFactory2方法,设置了自定义的onCreateView
  3. 跟随着Activity的生命周期,dispatch Fragment的状态

动态方式添加Fragment

val manager = supportFragmentManager
val beginTransaction = manager.beginTransaction()
val oneFragment = OneFragment()
beginTransaction.replace(R.id.dynamicContainer, oneFragment)
beginTransaction.commit()

FragmentTransaction中创建BackStackRecord

public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

FragmentTransactio#replace

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


void doAddOp(int containerViewId, Fragment fragment, @Nullable 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.");
    }
    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);
        }
        // 保存存放mContainerId
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }
    addOp(new Op(opcmd, fragment));
}

// Op的构造函数
Op(int cmd, Fragment fragment) {
    this.mCmd = cmd;
    this.mFragment = fragment;
    this.mOldMaxState = Lifecycle.State.RESUMED;
    this.mCurrentMaxState = Lifecycle.State.RESUMED;
}

ArrayList<Op> mOps = new ArrayList<>();

// 添加到Op集合中
void addOp(Op op) {
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

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#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();
        }
    }
}

private Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions(true);
    }
};

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;
}


private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isPop) {
    boolean didSomething = false;
    synchronized (mPendingActions) {
        if (mPendingActions.isEmpty()) {
            return false;
        }
        final int numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {
            didSomething |= mPendingActions.get(i).generateOps(records, isPop);
        }
        mPendingActions.clear();
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return didSomething;
}


// BackStackRecord
@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop) {
    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
        Log.v(TAG, "Run: " + this);
    }
    records.add(this);
    isRecordPop.add(false);
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
    return true;
}

// 去除多余的
    private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop) {
        if (records.isEmpty()) {
            return;
        }

        if (records.size() != isRecordPop.size()) {
            throw new IllegalStateException("Internal error with the back stack records");
        }

        // Force start of any postponed transactions that interact with scheduled transactions:
        executePostponedTransaction(records, isRecordPop);

        final int numRecords = records.size();
        int startIndex = 0;
        for (int recordNum = 0; recordNum < numRecords; recordNum++) {
            final boolean canReorder = records.get(recordNum).mReorderingAllowed;
            if (!canReorder) {
                // execute all previous transactions
                if (startIndex != recordNum) {
                    executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                }
                // execute all pop operations that don't allow reordering together or
                // one add operation
                int reorderingEnd = recordNum + 1;
                if (isRecordPop.get(recordNum)) {
                    while (reorderingEnd < numRecords
                            && isRecordPop.get(reorderingEnd)
                            && !records.get(reorderingEnd).mReorderingAllowed) {
                        reorderingEnd++;
                    }
                }
                executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
                startIndex = reorderingEnd;
                recordNum = reorderingEnd - 1;
            }
        }
        if (startIndex != numRecords) {
            executeOpsTogether(records, isRecordPop, startIndex, numRecords);
        }
    }



Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
    for (int opNum = 0; opNum < mOps.size(); opNum++) {
        final Op op = mOps.get(opNum);
        switch (op.mCmd) {
            case OP_ADD:
            case OP_ATTACH:
                added.add(op.mFragment);
                break;
            case OP_REMOVE:
            case OP_DETACH: {
                added.remove(op.mFragment);
                if (op.mFragment == oldPrimaryNav) {
                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
                    opNum++;
                    oldPrimaryNav = null;
                }
            }
            break;
            case OP_REPLACE: {
                final Fragment f = op.mFragment;
                final int containerId = f.mContainerId;
                boolean alreadyAdded = false;
                for (int i = added.size() - 1; i >= 0; i--) {
                    final Fragment old = added.get(i);
                    if (old.mContainerId == containerId) {
                        if (old == f) {
                            alreadyAdded = true;
                        } else {
                            // This is duplicated from above since we only make
                            // a single pass for expanding ops. Unset any outgoing primary nav.
                            if (old == oldPrimaryNav) {
                                mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
                                opNum++;
                                oldPrimaryNav = null;
                            }
                            final Op removeOp = new Op(OP_REMOVE, old);
                            removeOp.mEnterAnim = op.mEnterAnim;
                            removeOp.mPopEnterAnim = op.mPopEnterAnim;
                            removeOp.mExitAnim = op.mExitAnim;
                            removeOp.mPopExitAnim = op.mPopExitAnim;
                            mOps.add(opNum, removeOp);
                            added.remove(old);
                            opNum++;
                        }
                    }
                }
                if (alreadyAdded) {
                    mOps.remove(opNum);
                    opNum--;
                } else {
                    op.mCmd = OP_ADD;
                    added.add(f);
                }
            }
            break;
            case OP_SET_PRIMARY_NAV: {
                // It's ok if this is null, that means we will restore to no active
                // primary navigation fragment on a pop.
                mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
                opNum++;
                // Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
                oldPrimaryNav = op.mFragment;
            }
            break;
        }
    }
    return oldPrimaryNav;
}


    /**
     * Executes the operations contained within this transaction. The Fragment states will only
     * be modified if optimizations are not allowed.
     */
    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);
        }
    }

// FragmentStateManager
    FragmentStateManager addFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
        FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
        fragment.mFragmentManager = this;
        mFragmentStore.makeActive(fragmentStateManager);
        if (!fragment.mDetached) {
            mFragmentStore.addFragment(fragment);
            fragment.mRemoving = false;
            if (fragment.mView == null) {
                fragment.mHiddenChanged = false;
            }
            if (isMenuAvailable(fragment)) {
                mNeedMenuInvalidate = true;
            }
        }
        return fragmentStateManager;
    }

FragmentManager#显示在界面上

private void completeShowHideFragment(@NonNull final Fragment fragment) {
        if (fragment.mView != null) {
            FragmentAnim.AnimationOrAnimator anim = FragmentAnim.loadAnimation(
                    mHost.getContext(), fragment, !fragment.mHidden, fragment.getPopDirection());
            if (anim != null && anim.animator != null) {
                anim.animator.setTarget(fragment.mView);
                if (fragment.mHidden) {
                    if (fragment.isHideReplaced()) {
                        fragment.setHideReplaced(false);
                    } else {
                        final ViewGroup container = fragment.mContainer;
                        final View animatingView = fragment.mView;
                        container.startViewTransition(animatingView);
                        // Delay the actual hide operation until the animation finishes,
                        // otherwise the fragment will just immediately disappear
                        anim.animator.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                container.endViewTransition(animatingView);
                                animation.removeListener(this);
                                if (fragment.mView != null && fragment.mHidden) {
                                    fragment.mView.setVisibility(View.GONE);
                                }
                            }
                        });
                    }
                } else {
                    fragment.mView.setVisibility(View.VISIBLE);
                }
                anim.animator.start();
            } else {
                if (anim != null) {
                    fragment.mView.startAnimation(anim.animation);
                    anim.animation.start();
                }
                final int visibility = fragment.mHidden && !fragment.isHideReplaced()
                        ? View.GONE
                        : View.VISIBLE;
                fragment.mView.setVisibility(visibility);
                if (fragment.isHideReplaced()) {
                    fragment.setHideReplaced(false);
                }
            }
        }
        invalidateMenuForFragment(fragment);
        fragment.mHiddenChanged = false;
        fragment.onHiddenChanged(fragment.mHidden);
    }

show 是直接addView
commit 是setVisible

事务内存管理

入栈:
mIndex = mManager.allocBackStackIndex(this);
mBackStackIndices.add(bse);

出栈:
freeBackStackIndex()

mTmpRecords,mTmpRecords

四种不同的提交方式

commit

正常的方式

commitInternal -> enqueueAction -> scheduleCommit -> execPendingActions -> startPendingDeferredFragments -> performPendingDeferredStart -> fragmentStateManager.moveToExpectedState() -> controller.enqueueShow( -> 显示界面

很多个操作放在一起,通过handler的post调用

commitAllowingStateLoss

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();
        }

commitNow

@Override
    public void commitNow() {
        disallowAddToBackStack(); // 设置标识位mAllowAddToBackStack = false;
        mManager.execSingleAction(this, false);
    }

    void execSingleAction(@NonNull OpGenerator action, boolean allowStateLoss) {
        if (allowStateLoss && (mHost == null || mDestroyed)) {
            // This FragmentManager isn't attached, so drop the entire transaction.
            return;
        }
        ensureExecReady(allowStateLoss);
        // 直接放入mTmpRecords中, 然后去掉冗余操作
        if (action.generateOps(mTmpRecords, mTmpIsPop)) {
            mExecutingActions = true;
            try {
                removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
            } finally {
                cleanupExec();
            }
        }

        updateOnBackPressedCallbackEnabled();
        doPendingDeferredStart(); // 开始执行流程
        mFragmentStore.burpActive();
    }
execSingleAction -> startPendingDeferredFragments -> performPendingDeferredStart -> fragmentStateManager.moveToExpectedState() -> controller.enqueueShow(

直接在主线程调用

commitNowAllowingStateLoss

其它

Activity和Fragment的通信方式, Fragment之间如何进行通信

Activity和Fragment
1.采用Bundle的方式 在activity中建一个bundle,把要传的值存入bundle,然后通过fragment的
setArguments(bundle)传到fragment,在fragment中,用getArguments接收。
2.采用接口回调的方式
3.EventBus的方式
4.viewModel 做数据管理,activity 和 fragment 公用同个viewModel 实现数据传递
Fragment之间
1.EventBus的方式
2.采用接口回调的方式
3.Fragment 通过 getActivity 获取到Activity,Activity通过findFragmentByTag||findFragmentById获取
Fragment,Fragment 实现接口.

为什么使用Fragment.setArguments(Bundle)传递参数

https://www.jianshu.com/p/c06efe090589 Activity.onCreate(Bundle saveInstance)->Fragment.instantitate()
当再次重建时会通过空参构造方法反射出新的fragment。并且给mArgments初始化为原先的值,而原来的
Fragment实例的数据都丢失了。
Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过
Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来,并在重建时恢复。所以,尽量使用
Fragment.setArguments(Bundle bundle)方式来进行参数传递。

FragmentPageAdapter和FragmentStatePageAdapter区别及使用场景

使用FragmentPagerAdapter时页面切换,只是调用detach,而不是remove,所以只执行onDestroyView,而不是onDestroy,不会摧毁Fragment实例,只会摧毁Fragment 的View;
使用FragmentStatePageAdapter时页面切换,调用remove,执行onDestroy。直接摧毁Fragment。
FragmentPagerAdapter最好用在少数静态Fragments的场景,用户访问过的Fragment都会缓存在内存中,即
使其视图层次不可见而被释放(onDestroyView) 。因为Fragment可能保存大量状态,因此这可能会导致使用大量内存。
页面很多时,可以考虑FragmentStatePagerAdapter

fragment懒加载

判断当前 Fragment 是否对用户可见,只是 onHiddenChanged() 是在 add+show+hide 模式下使用,
setUserVisibleHint 是在 ViewPager+Fragment 模式下使用。

老的懒加载处理方案
对 ViewPager 中的 Fragment 懒加载

  • 方法1: 继承模式
    通过继承懒加载Fragment基类,在setUserVisibleHint中判断可见并且当onViewCreated()表明View已经加载完毕后再掉用加载方法。
  • 方法2:代理+反射模式
    1.adapter中getitem时new一个代理fragment
    2.setUserVisibleHint中根据反射得到真正的fragement
    3.通过add commit把真正的fragement添加到代理fragment中
    方法1:不可见的 Fragment 执行了 onResume() 方法。因为setUserVisibleHint位于onCreateView之前,此时为false,onResume之后为true,在true后加载相当于onResume()等方法在真实的createView之前调用,不可见的Fragment 执行了 onResume() 方法。

Androidx 下的懒加载
在 FragmentPagerAdapter 与 FragmentStatePagerAdapter 新增了含有 behavior 字段的构造函数如果 behavior 的值为 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT ,那么当前选中的 Fragment 在Lifecycle.State#RESUMED 状态 ,其他不可见的 Fragment 会被限制在 Lifecycle.State#STARTED 状态原因:FragmentPagerAdapter 在其 setPrimaryItem 方法中调用了 setMaxLifecycle, 所以说onResume中执行懒加载

ViewPager2与ViewPager区别


  1. FragmentStateAdapter 替代FragmentStatePagerAdapter,PagerAdapter被RecyclerView.Adapter替代
  2. 支持竖直滑动,禁止滑动
  3. PageTransformer用来设置页面动画,设置页面间距
  4. 预加载当setOffscreenPageLimit被设置为OFFSCREEN_PAGE_LIMIT_DEFAULT时候会使用RecyclerView的
    缓存机制。


标签:java,androidx,Fragment,ViewPager,StackTraceElement,fragment,final,op
From: https://blog.51cto.com/u_11797608/6405142

相关文章

  • linphone-去掉HistoryListFragment界面
    说明HistoryListFragment界面包括:1.拨打电话记录2.未接听记录3.修改记录看图HistoryListFragment主界面修改拨打记录界面好,开始去掉这个界面需要分析的点每次拨打记录是怎样形成的。记录还可以分日期显示一组。没有接到的电话是怎样记录的就该记录时,那个工具栏是怎样变......
  • 常见问题解决 --- Failed to build android app at server - class file for android.
    问题原因  这个错误主要是LocalBroadcastManager这个类被弃用了,而在库或者sdk中使用到了。解决办法build.gradle文件中添加implementation'com.android.support:support-v4:30.4.1'gradle.properties添加android.enableJetifier=true......
  • Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面
    感觉Android到处都是坑,每个地方都要把人折腾半天。今天来简单说说Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面关于他们的介绍就不多说了,网上到处都是,只说关键的部分:我在开发的时候遇到几个疑难问题,花费大量时间处理,总结如下:1.关于Fragment内部......
  • Android Fragment完全解析,关于碎片你所需知道的一切
    我们都知道,Android上的界面展示都是通过Activity实现的,Activity实在是太常用了,我相信大家都已经非常熟悉了,这里就不再赘述。但是Activity也有它的局限性,同样的界面在手机上显示可能很好看,在平板上就未必了,因为平板的屏幕非常大,手机的界面放在平板上可能会有......
  • Android 动态改变 navigation 的 startDestination, 使得已登录的用户直接跳过 LoginF
    需求:未登录用户打开App,会展示登录页面LoginFragment已登录用户打开App,直接展示MainFragmentnav_graph.xml结构如下:MainActivity.java:@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);......
  • Duplicate class androidx.lifecycle.ViewModelLazy found in modules lifecycle-view
    AS版本:AndroidStudioBumblebee|2021.1.1Patch1Build#AI-211.7628.21.2111.8139111,builtonFebruary2,2022Runtimeversion:11.0.11+9-b60-7590822amd64VM:OpenJDK64-BitServerVMbyOracleCorporationWindows1010.0GC:G1YoungGeneration,G1OldGene......
  • 直播app系统源码,dialogfragment设置底部没有和屏幕有间隔
    直播app系统源码,dialogfragment设置底部没有和屏幕有间隔 @Override  publicvoidonStart(){    super.onStart();    Windowwindow=getDialog().getWindow();    if(window!=null){      //设置window的背景色为透明色. ......
  • 第六节:受控 、高阶组件、portals、fragment、严格模式、动画
    一.受控组件       二.高阶组件       三.portals      四.fragment        五.严格模式        六.动画         !作       者:Yaopengfei(姚鹏飞)博客地......
  • 使用 youth5201314:banner 库时出现 ViewPager 或 xandroid 报错
    使用youth5201314:banner这个库的1.4.10版本开发时,Build时报错找不到android.support.v4.view.ViewPager的类文件找不到androidx.fragment.app.Fragment的类文件需要在Project的gradle.properties配置文件中加一行,用于自动迁移第三方库android.enableJetifier=......
  • activity嵌套fragment 并 启动activity
    1.MainActivityFragmentManagerfragmentManager;FragmentTransactiontransaction;privatevoidreplaceFragment(Fragmentfragment){//1.获取FragmentManager,在活动中可以直接通过调用getFragmentManager()方法得到fragmentManager=getSupportFragme......