美文网首页工作生活
开发者模式不保留活动, Fragment出现重影

开发者模式不保留活动, Fragment出现重影

作者: 醉了俗身醒了初心 | 来源:发表于2019-06-30 21:50 被阅读0次

    原因:

    使用 Fragment 的状态保存,当系统内存不足,Fragment 的宿主 Activity 回收的时候,
    Fragment 的实例并没有随之被回收。Activity 被系统回收时,会主动调用 onSaveInstance() 
    方法来保存视图层(View Hierarchy),所以当 Activity 通过导航再次被重建时,
    之前被实例化过的 Fragment 依然会出现在 Activity 中,此时的 FragmentTransaction 中的
    相当于又再次 add 了 fragment 进去的,hide()和show()方法对之前保存的fragment已经
    失效了。综上这些因素导致了多个Fragment重叠在一起。
    

    解决方法:

    第一种

    1.给每个 Fragment 加一个 Tag
    2.在 onCreate(Bundle savedInstanceState) 中判断 Bundle savedInstanceState 是否不为空
    3.不为空则进行 find Tag,重新给几个 frament 赋值
    这样子仍是对之前保存的 fragment 操作,成功解决了重叠的问题。
    
    

    kotlin写法

    class MainActivity : AppCompatActivity() {
    
        private var mHomeFragment: HomeFragment? = null
        private var mMessageFragment: MessageFragment? = null
        private var mMineFragment: MineFragment? = null
        private var mPreFragment: Fragment? = null
        private lateinit var mTransaction: FragmentTransaction
    
    
        override fun onCreate(savedInstanceState: Bundle?) {
            mTransaction = supportFragmentManager.beginTransaction()
            //savedInstanceState不为空, 状态恢复时, 重新查找一遍, 重新赋值
            savedInstanceState?.let {
                mHomeFragment = mHomeFragment ?: supportFragmentManager.findFragmentByTag("0") as HomeFragment
                mMessageFragment = mMessageFragment ?: supportFragmentManager.findFragmentByTag("1") as MessageFragment
                mMineFragment = mMineFragment ?: supportFragmentManager.findFragmentByTag("2") as MineFragment
            }
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            initData()
        }
    
        private fun initData() {
            //选中监听
            mRgBottomMenu.setOnCheckedChangeListener { _, checkedId ->
                val transaction = supportFragmentManager.beginTransaction()
                mPreFragment?.let {
                    transaction.hide(it)
                }
                when (checkedId) {
                    R.id.mRbHome -> //home界面
                        mHomeFragment =
                            mHomeFragment?.apply { showFragment(transaction, this) }
                            ?: addFragment(transaction, 0) as HomeFragment
    
                    R.id.mRbMessage ->//消息界面
                        mMessageFragment =
                            mMessageFragment?.apply { showFragment(transaction, this) }
                                ?: addFragment(transaction, 1) as MessageFragment
    
                    R.id.mRbMine -> //我的界面
                        mMineFragment =
                            mMineFragment?.apply { showFragment(transaction, this) }
                                ?: addFragment(transaction, 2) as MineFragment
                }
                transaction.commitAllowingStateLoss()
            }
            mRbHome.isChecked = true
        }
    
        //显示已经存在的fragment
        private fun showFragment(transaction: FragmentTransaction, fragment: Fragment) {
            transaction.show(fragment)
            mPreFragment = fragment
            Log.d("test:: ", "show: ${fragment::class.java.simpleName} - $fragment")
        }
    
        //添加第一次创建实例的fragment
        private fun addFragment(transaction: FragmentTransaction, type: Int): Fragment {
            val fragment = when (type) {
                0 -> HomeFragment()
                1 -> MessageFragment()
                else -> MineFragment()
            }
            transaction.add(R.id.mFlRoot, fragment, "$type")
            mPreFragment = fragment
            Log.d("test:: ", "add: ${fragment::class.java.simpleName} - $fragment")
            return fragment
        }
    }
    

    java写法

    public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {
        private TextView mTvTitle;
        private LinearLayout mLlActionbar;
        private FrameLayout mFlRoot;
        private RadioButton mRbHome;
        private RadioButton mRbMessage;
        private RadioButton mRbMine;
        private RadioGroup mRgBottomMenu;
    
    
        private HomeFragment mHomeFragment;
        private MessageFragment mMessageFragment;
        private MineFragment mMineFragment;
        private Fragment mPreFragment;
        private FragmentManager mFragmentManager;
    
    
        @Override
    
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            mFragmentManager = getSupportFragmentManager();
            super.onCreate(savedInstanceState);
            if (savedInstanceState != null) {
                mHomeFragment = (HomeFragment) mFragmentManager.findFragmentByTag("HomeFragment");
                mMessageFragment = (MessageFragment) mFragmentManager.findFragmentByTag("MessageFragment");
                mMineFragment = (MineFragment) mFragmentManager.findFragmentByTag("MineFragment");
            }
            setContentView(R.layout.activity_main);
            initView();
            initData();
            initListener();
        }
        //可要可不要
        @Override
        public void onAttachFragment(@NonNull Fragment fragment) {
    //        if (mHomeFragment == null && fragment instanceof HomeFragment) {
    //            mHomeFragment = (HomeFragment) fragment;
    //        } else if (mMessageFragment == null && fragment instanceof MessageFragment) {
    //            mMessageFragment = (MessageFragment) fragment;
    //        } else if (mMineFragment == null && fragment instanceof MineFragment) {
    //            mMineFragment = (MineFragment) fragment;
    //        }
        }
    
        private void initView() {
    
            mTvTitle = findViewById(R.id.mTvTitle);
            mLlActionbar = findViewById(R.id.mLlActionbar);
            mFlRoot = findViewById(R.id.mFlRoot);
            mRbHome = findViewById(R.id.mRbHome);
            mRbMessage = findViewById(R.id.mRbMessage);
            mRbMine = findViewById(R.id.mRbMine);
            mRgBottomMenu = findViewById(R.id.mRgBottomMenu);
        }
    
        private void initData() {
    
        }
    
        private void initListener() {
            mRgBottomMenu.setOnCheckedChangeListener(this);
    //        mRgBottomMenu.check(R.id.mRbHome);
            mRbHome.setChecked(true);
        }
    
    
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            FragmentTransaction transaction = mFragmentManager.beginTransaction();
            if (mPreFragment != null) {
                transaction.hide(mPreFragment);
            }
            switch (checkedId) {
                case R.id.mRbHome:
                    if (mHomeFragment == null) {
                        mHomeFragment = new HomeFragment();
                        transaction.add(R.id.mFlRoot, mHomeFragment, "HomeFragment");
                    } else {
                        transaction.show(mHomeFragment);
                    }
                    mPreFragment = mHomeFragment;
                    break;
                case R.id.mRbMessage:
                    if (mMessageFragment == null) {
                        mMessageFragment = new MessageFragment();
                        transaction.add(R.id.mFlRoot, mMessageFragment, "MessageFragment");
                    } else {
                        transaction.show(mMessageFragment);
                    }
                    mPreFragment = mMessageFragment;
                    break;
                case R.id.mRbMine:
                    if (mMineFragment == null) {
                        mMineFragment = new MineFragment();
                        transaction.add(R.id.mFlRoot, mMineFragment, "MineFragment");
                    } else {
                        transaction.show(mMineFragment);
                    }
                    mPreFragment = mMineFragment;
                    break;
            }
            transaction.commitAllowingStateLoss();
    
        }
    }
    

    第二种

    Activity 中的 onSaveInstanceState() 里面有一句super.onSaveInstanceState(outState);,
    Google 对于这句话的解释是 “Always call the superclass so it can save the view hierarchy state”,
    大概意思是“总是执行这句代码来调用父类去保存视图层的状态”。通过注释掉这句话,
    这样主 Activity 因为种种原因被回收的时候就不会保存之前的 fragment state,
    也可以成功解决重叠的问题。
    
    @Override
        protected void onSaveInstanceState(@NonNull Bundle outState) {
    //        super.onSaveInstanceState(outState);
        }
    

    fragment 回退栈有关问题

    通常使用fragmentManager.beginTransaction().addToBackStack(null);  
    
    但是也经常会遇到说“某个fragment”已经被添加的错误,这往往是我们在对fragment进行返回处理时出现问题。这样的问题最常出现在我们点击界面进行跳转的时候。
    
    一般情况,当我们点击导航栏进行界面切换之后,之前back stack中保存的fragment也就不再需要保留了。用下面的语句可以将back stack清空,同时也可避免上述错误的出现。
    
    FragmentManager fragmentManager=getSupportFragmentManager();  
    fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);  
    
    

    相关文章

      网友评论

        本文标题:开发者模式不保留活动, Fragment出现重影

        本文链接:https://www.haomeiwen.com/subject/kahicctx.html