Android Fragment的add,show,hide一定要一起用吗?

Fragment的add,show,hide一定要一起用吗?

问题

两个fragment, fragmentTest1和fragmentTest2, 初始化fragmentTest1, 代码如下:

supportFragmentManager.beginTransaction()
    .add(R.id.content, fragmentTest1, FragmentTest1::class.java.simpleName)
    .commit()

然后在一个点击事件跳转到fragmentTest2, 代码如下:

val fragmentTest2 = FragmentTest2()
supportFragmentManager.beginTransaction().apply {
add(R.id.content, fragmentTest2,"FragmentTest2")
    .show(fragmentTest2)
    .addToBackStack(null)
    .commit()
}

很明显跳转没有加hide(fragmentTest1), 那么这里会发生什么问题呢?

我们打印一下他们的生命周期,如下:

fragmentTest1: onViewCreated
fragmentTest1: onResume
fragmentTest2: onViewCreated
fragmentTest2: onResume

为啥fragmentTest1仍然可见, 问题出现在这了, 我们只能乖乖的加上hide(fragment1),逻辑才正常. 这是为什么呢.

加上hide之后, 需要重写onHiddenChanged来监听, 因为hide操作不会回调onPause

源码分析

分析一下add,shou,hide到底做了些什么操作导致onHiddenChanged的回调.

commit
public int commit() {
        return commitInternal(false);
    }


int commitInternal(boolean allowStateLoss) {
        //省略

        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }


//后面的跳转省略, 给出跳转的方法, 主要是事务抛到fragment的handler去执行
scheduleCommit();
到
mHost.getHandler().post(mExecCommit);

mExecCommit的定义如下: 
Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};
execPendingActions
  public boolean execPendingActions() {
        ensureExecReady(true);

        //后面省略
    }

 private void ensureExecReady(boolean allowStateLoss) {
 		//...
        try {
            executePostponedTransaction(null, null);
        } finally {
            mExecutingActions = false;
        }
    }

private void executePostponedTransaction(ArrayList<BackStackRecord> records,
                                             ArrayList<Boolean> isRecordPop) {
    //遍历mPostponedTransactions
    //
	listener.completeTransaction();
    }
completeTransaction
 public void completeTransaction() {
 			//省略标记
            mRecord.mManager.completeExecute(mRecord, mIsBack, !canceled, true);
        }

终于到达完成事务的地方
 void completeExecute(BackStackRecord record, boolean isPop, boolean runTransitions,
                         boolean moveToState) {
        if (isPop) {
        	//出栈
            record.executePopOps(moveToState);
        } else {
        	//进栈
            record.executeOps();
        }

        //省略
}

excuteOps

这个方法非常多的操作, 都是我们调用add, hide, show的时候添加进来的Op对象

这里看看hideFragmnet

 public void hideFragment(Fragment fragment) {
        if (DEBUG) Log.v(TAG, "hide: " + fragment);
        if (!fragment.mHidden) {
            fragment.mHidden = true;
            // Toggle hidden changed so that if a fragment goes through show/hide/show
            // it doesn't go through the animation.
            fragment.mHiddenChanged = !fragment.mHiddenChanged;
        }
    }

真相大白, 看到mHiddenChanged被修改了. 但是哪里通知fragment的呢?

在做完一系列的add,hide,show之后, 会调用moveToState, 然后会调用moveFragmentToExpectedState, 最后有一句:

if (f.mHiddenChanged) {
	completeShowHideFragment(f);
}

最后会调用

fragment.mHiddenChanged = false;
fragment.onHiddenChanged(fragment.mHidden);

看完这里, 我们把onHiddenChanged的路径找到了.

总结

Fragment的add,show,hide一定要一起用才能保证生命周期.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值