У меня есть действие, которое использует фрагменты для изменения экрана.Я загружаю эти фрагменты в FrameLayout
.
Activity: (я удалил не важные части)
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activities.HomeActivity"
android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/content_frame_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.drawerlayout.widget.DrawerLayout>
Внутри content_frame
я загружаю фрагменты, и это работает, находят,с одним исключением.В одном из этих фрагментов есть другой FrameLayout
, в котором я выбираю два разных фрагмента.Когда я загружаю этот фрагмент, все работает нормально, и я могу переключаться между двумя фрагментами.Но когда я оставляю фрагмент и снова открываю его, фрагмент внутри фрагмента не загружается.Иногда это также приводит к сбою:
2019-06-15 12:28:54.378 20353-20353/com.financetracker.financetracker E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.financetracker.financetracker, PID: 20353
java.lang.IllegalStateException: Restarter must be created only during owner's initialization stage
at androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.java:59)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2595)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:831)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1228)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1293)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2066)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1856)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1811)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1717)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
Редактировать: Статистика фрагмента (загружается в content_frame
:
class StatsFragment: Fragment() {
private lateinit var tvSortCategories: TextView
private lateinit var tvSortMonths: TextView
private var x: Float? = null
private val fragmentStatsCat = StatsCategoryFragment()
private val fragmentStatsMon = StatsMonthFragment()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_stats, container, false)
tvSortCategories = view.findViewById(R.id.tvStatsCategories)
tvSortMonths = view.findViewById(R.id.tvStatsMonths)
tvSortCategories.isSelected = true
tvSortCategories.setOnClickListener {
inflateCategory()
}
tvSortMonths.setOnClickListener {
inflateMonth()
}
}
private fun inflateCategory() {
tvSortCategories.isSelected = true
tvSortMonths.isSelected = false
fragmentManager!!.beginTransaction().setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right).replace(R.id.stats_container, fragmentStatsCat).commit()
}
private fun inflateMonth() {
tvSortCategories.isSelected = false
tvSortMonths.isSelected = true
fragmentManager!!.beginTransaction().setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left).replace(R.id.stats_container, fragmentStatsMon).commit()
}
}
Статистика фрагмента1 (загружается в FrameLayout
приведенный выше фрагмент)
class StatsMonthFragment: Fragment() {
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
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(categories.isEmpty()) {
cbAllCats.visibility = View.GONE
btnPrevCat.visibility = View.GONE
btnNextCat.visibility = View.GONE
//In Statistik schreiben, dass nichts vorhanden ist
} else {
val initFragment = StatsSelectedFilterFragment()
initFragment.setText(categories[i].cat_name)
fragmentManager!!.beginTransaction().add(R.id.container_stats_categories, initFragment).commit()
btnNextCat.setOnClickListener {
increaseIndex()
val fragment = StatsSelectedFilterFragment()
fragment.setText(categories[i].cat_name)
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
.replace(R.id.container_stats_categories, fragment)
.commit()
}
btnPrevCat.setOnClickListener {
decreaseIndex()
val fragment = StatsSelectedFilterFragment()
fragment.setText(categories[i].cat_name)
fragmentManager!!.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) {
btnPrevCat.isClickable = false
btnNextCat.isClickable = false
btnNextCat.isEnabled = false
btnPrevCat.isEnabled = false
val fragment = StatsSelectedFilterFragment()
fragment.setText(getString(R.string.all_categories))
fragmentManager!!.beginTransaction()
.replace(R.id.container_stats_categories, fragment)
.commit()
} else {
btnPrevCat.isClickable = true
btnNextCat.isClickable = true
btnNextCat.isEnabled = true
btnPrevCat.isEnabled = true
val fragment = StatsSelectedFilterFragment()
fragment.setText(categories[i].cat_name)
fragmentManager!!.beginTransaction()
.replace(R.id.container_stats_categories, fragment)
.commit()
}
}
}
return view
}
private fun increaseIndex() {
if(i == categories.size - 1) {
i = 0
} else {
i++
}
}
private fun decreaseIndex() {
if(i == 0) {
i = categories.size - 1
} else {
i--
}
}
private fun createNewGraph() {
}
}
Frags Stats2 (также загружается в вышеуказанный фрагмент Stats
)
class StatsCategoryFragment: Fragment() {
private lateinit var btnPrevYear: ImageButton
private lateinit var btnNextYear: ImageButton
private lateinit var btnPrevMonth: ImageButton
private lateinit var btnNextMonth: ImageButton
private lateinit var cbEntYear: CheckBox
private val cal = Calendar.getInstance()
private var curMonth: Int? = null
private var curYear: Int? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_stats_categories, container, false)
btnPrevYear = view.findViewById(R.id.btn_prev_year)
btnNextYear = view.findViewById(R.id.btn_next_year)
btnPrevMonth = view.findViewById(R.id.btn_prev_month)
btnNextMonth = view.findViewById(R.id.btn_next_month)
cbEntYear = view.findViewById(R.id.cb_entire_year)
curYear = cal.get(Calendar.YEAR)
curMonth = cal.get(Calendar.MONTH) + 1
val monthFragment = StatsSelectedFilterFragment()
monthFragment.setText(getMonthString(getMonthEnum(curMonth!!)!!))
val yearFragment = StatsSelectedFilterFragment()
yearFragment.setText(curYear!!.toString())
fragmentManager!!.beginTransaction().add(R.id.container_stats_month, monthFragment).commit()
fragmentManager!!.beginTransaction().add(R.id.container_stats_year, yearFragment).commit()
btnPrevYear.setOnClickListener {
decreaseYear()
val fragment = StatsSelectedFilterFragment()
fragment.setText(curYear.toString())
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.container_stats_year, fragment)
.commit()
}
btnNextYear.setOnClickListener {
increaseYear()
val fragment = StatsSelectedFilterFragment()
fragment.setText(curYear.toString())
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
.replace(R.id.container_stats_year, fragment)
.commit()
}
btnPrevMonth.setOnClickListener {
val decYear = decreaseMonth()
val fragment = StatsSelectedFilterFragment()
fragment.setText(getMonthString(getMonthEnum(curMonth!!)!!))
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.container_stats_month, fragment)
.commit()
if(decYear) {
val fragmentY = StatsSelectedFilterFragment()
fragmentY.setText(curYear.toString())
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.container_stats_year, fragmentY)
.commit()
}
}
btnNextMonth.setOnClickListener {
val incYear = increaseMonth()
val fragment = StatsSelectedFilterFragment()
fragment.setText(getMonthString(getMonthEnum(curMonth!!)!!))
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
.replace(R.id.container_stats_month, fragment)
.commit()
if(incYear) {
val fragmentY = StatsSelectedFilterFragment()
fragmentY.setText(curYear.toString())
fragmentManager!!.beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
.replace(R.id.container_stats_year, fragmentY)
.commit()
}
}
cbEntYear.setOnCheckedChangeListener {_, checked->
if(checked) {
btnPrevMonth.isClickable = false
btnNextMonth.isClickable = false
btnPrevMonth.isEnabled = false
btnNextMonth.isEnabled = false
val fragment = StatsSelectedFilterFragment()
fragment.setText(getString(R.string.every_month))
fragmentManager!!.beginTransaction().replace(R.id.container_stats_month, fragment).commit()
} else {
btnPrevMonth.isClickable = true
btnNextMonth.isClickable = true
btnPrevMonth.isEnabled = true
btnNextMonth.isEnabled = true
val fragment = StatsSelectedFilterFragment()
fragment.setText(getMonthString(getMonthEnum(curMonth!!)!!))
fragmentManager!!.beginTransaction()
.replace(R.id.container_stats_month, fragment)
.commit()
}
}
return view
}
private enum class Month {
JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
}
private fun getMonthEnum(month: Int): Month? {
return when(month) {
1 -> Month.JANUARY
2 -> Month.FEBRUARY
3 -> Month.MARCH
4 -> Month.APRIL
5 -> Month.MAY
6 -> Month.JUNE
7 -> Month.JULY
8 -> Month.AUGUST
9 -> Month.SEPTEMBER
10 -> Month.OCTOBER
11 -> Month.NOVEMBER
12 -> Month.DECEMBER
else -> null
}
}
private fun getMonthString(month: Month): String {
return when (month) {
Month.JANUARY -> getString(R.string.january)
Month.FEBRUARY -> getString(R.string.february)
Month.MARCH -> getString(R.string.march)
Month.APRIL -> getString(R.string.april)
Month.MAY -> getString(R.string.may)
Month.JUNE -> getString(R.string.june)
Month.JULY -> getString(R.string.july)
Month.AUGUST -> getString(R.string.august)
Month.SEPTEMBER -> getString(R.string.september)
Month.OCTOBER -> getString(R.string.october)
Month.NOVEMBER -> getString(R.string.november)
Month.DECEMBER -> getString(R.string.december)
}
}
private fun increaseMonth(): Boolean {
return if(curMonth == 12) {
curMonth = 1
increaseYear()
true
} else {
curMonth = curMonth!! + 1
false
}
}
private fun decreaseMonth(): Boolean {
return if(curMonth == 1) {
curMonth = 12
decreaseYear()
true
} else {
curMonth = curMonth!! - 1
false
}
}
private fun increaseYear() {
curYear = curYear!! + 1
}
private fun decreaseYear() {
curYear = curYear!! - 1
}
private fun createNewGraph() {
}
}