我有一个片段类,其中包含带有两个站点的ViewPager。这些网站包含一些小工具,例如CheckBoxes,我希望它们在方向改变时保持选中状态。
MainFragment:
class StatsFragment: Fragment() {
private val fragmentStatsCat = StatsCategoryFragment()
private val fragmentStatsMon = StatsMonthFragment()
private lateinit var pager: ViewPager
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_stats, container, false)
pager = view.findViewById(R.id.stats_container)
val pagerAdapter = StatsScreenSlidePagerAdapter(childFragmentManager)
pager.adapter = pagerAdapter
return view
}
private inner class StatsScreenSlidePagerAdapter(fm: FragmentManager): FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment {
return if (position == 0) {
fragmentStatsCat
} else {
fragmentStatsMon
}
}
override fun getCount(): Int = 2
override fun saveState(): Parcelable? {
return null
}
}
}
其中一个ViewPagerFragments:
class StatsMonthFragment: Fragment() {
companion object {
private const val CHECKBOX_KEY = "isChecked"
private const val CATEGORY_KEY = "category"
}
private lateinit var btnPrevCat: ImageButton
private lateinit var btnNextCat: ImageButton
private lateinit var cbAllCats: CheckBox
private lateinit var categories: List<Category>
private var i: Int = 0
private var isCbChecked: Boolean? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState != null) {
i = savedInstanceState.getInt(CATEGORY_KEY)
isCbChecked = savedInstanceState.getBoolean(CHECKBOX_KEY)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_stats_months, container, false)
btnNextCat = view.findViewById(R.id.btn_next_cat)
btnPrevCat = view.findViewById(R.id.btn_prev_cat)
cbAllCats = view.findViewById(R.id.cb_all_cats)
categories = DatabaseInitializer.getInstance().getAllCategories(AppDatabase.getInstance(context).categoryDao())
if(isCbChecked == null || isCbChecked!!) {
val initFragment = StatsSelectedFilterFragment() //This is just a fragment with a TextView; I use fragments for that for the CustomAnimations
initFragment.setText(categories[i].cat_name)
childFragmentManager.beginTransaction().add(R.id.container_stats_categories, initFragment).commit()
} else {
val fragment = StatsSelectedFilterFragment()
fragment.setText(getString(R.string.all_categories))
childFragmentManager.beginTransaction()
.replace(R.id.container_stats_categories, fragment)
.commit()
}
btnNextCat.setOnClickListener {
val fragment = StatsSelectedFilterFragment()
fragment.setText(categories[i].cat_name)
childFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
.replace(R.id.container_stats_categories, fragment)
.commit()
}
btnPrevCat.setOnClickListener {
val fragment = StatsSelectedFilterFragment()
fragment.setText(categories[i].cat_name)
childFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.container_stats_categories, fragment)
.commit()
}
cbAllCats.setOnCheckedChangeListener{_,checked->
if(checked) {
val fragment = StatsSelectedFilterFragment()
fragment.setText(getString(R.string.all_categories))
childFragmentManager.beginTransaction()
.replace(R.id.container_stats_categories, fragment)
.commit()
} else {
val fragment = StatsSelectedFilterFragment()
fragment.setText(categories[i].cat_name)
childFragmentManager.beginTransaction()
.replace(R.id.container_stats_categories, fragment)
.commit()
}
}
return view
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val isAllCatsChecked = cbAllCats.isChecked
outState.putBoolean(CHECKBOX_KEY, isAllCatsChecked)
outState.putInt(CATEGORY_KEY, i)
}
}
现在,每次屏幕旋转时,片段都会被重新创建两次,首先使用savedInstanceState != null
,然后使用savedInstanceState == null
,这意味着我无权访问Fragments中的旧设置。据我所知,这是因为重新创建了片段,然后还重新创建了包含viewpager的MainFragment,这意味着第二次创建了viewPager中的片段。我已经在MainFragment中尝试过类似的事情:
private lateinit var fragmentStatsCat: StatsCategoryFragment
private lateinit var fragmentStatsMon: StatsMonthFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null) {
fragmentStatsMon = StatsMonthFragment()
fragmentStatsCat = StatsCategoryFragment()
} else {
//Finding old fragments
}
}
也许这可以解决问题(我不确定),但是我不知道如何找到这些片段,因为它们位于ViewPager中。
编辑 我现在找到了一种在重新创建活动时查找碎片的解决方案:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null)
{
fragmentStatsMon = StatsMonthFragment()
fragmentStatsCat = StatsCategoryFragment()
} else {
fragmentStatsMon = childFragmentManager.getFragment(savedInstanceState, FRAG_MONTH_TAG) as StatsMonthFragment
fragmentStatsCat = childFragmentManager.getFragment(savedInstanceState, FRAG_CAT_TAG) as StatsCategoryFragment
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
childFragmentManager.putFragment(outState, FRAG_CAT_TAG, fragmentStatsCat)
childFragmentManager.putFragment(outState, FRAG_MONTH_TAG, fragmentStatsMon)
}
这会在Bundle
中添加一个引用,之后可以使用该引用获取片段。但是现在,我还有另一个问题。重新创建活动时,它将引发以下异常:
java.lang.IllegalStateException: Fragment already added: StatsCategoryFragment{f06ec65 (a1991f39-3af4-4a74-9aeb-79274beae04a) id=0x7f09014a}
我不知道如何解决这个问题,因为我并没有真正手动添加片段。另外,我真的不明白,因为viewpager和适配器也被重新创建了,不是吗?那么,为什么碎片仍然附着在适配器上呢?
我也不知道发生在哪一行代码,我既无法在logcat中找到它,也无法通过调试找到它。
答案 0 :(得分:0)
将此行放在要加载片段的“活动”条目的AndroidManifest.xml中:
decimal
通过这种方式,在任何情况下重新创建您的片段时,数据都不会重置。
示例:
android:configChanges="layoutDirection|keyboardHidden|orientation|screenSize"
答案 1 :(得分:0)