java.lang.IllegalStateException:片段已添加:MovieFragment
java.lang.IllegalStateException: Fragment already added: MovieFragment
在我的 MyPagerAdapter class 上添加了错误片段,它扩展了 FragmentPagerAdapter
这是我的错误日志
E/AndroidRuntime: FATAL EXCEPTION: main
Process: id.cahyowhy.tmdbmovieimplementation, PID: 8228
java.lang.IllegalStateException: Fragment already added: MovieFragment{df79747} (01cf33b8-9eb3-4dce-9519-384ca7dd7570) id=0x7f08014e android:switcher:2131231054:0}
at androidx.fragment.app.FragmentStore.addFragment(FragmentStore.java:67)
at androidx.fragment.app.FragmentManager.addFragment(FragmentManager.java:1563)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:405)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
at androidx.fragment.app.FragmentManager.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
这是我的 pageradapter 代码
class MyPagerAdapter(fm: FragmentManager) :
FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val pages = listOf(
MovieFragment.newInstance(MovieListType.POPULAR),
MovieFragment.newInstance(MovieListType.TOP_RATED),
MovieFragment.newInstance(MovieListType.UPCOMING)
)
override fun getItem(position: Int): Fragment {
return pages[position]
}
override fun getCount(): Int {
return pages.size
}
override fun getPageTitle(position: Int): CharSequence? {
return when (position) {
0 -> "Popular"
1 -> "Top Rated"
else -> "Up Coming"
}
}
}
这是我的电影片段代码
package id.cahyowhy.tmdbmovieimplementation.ui.activity.fragment
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import id.cahyowhy.tmdbmovieimplementation.databinding.MoviesFragmentResultBinding
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.ItemTypeFactoryImpl
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.VisitableRecyclerAdapter
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.viewholder.ErrorStateItem
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.viewholder.MovieItem
import id.cahyowhy.tmdbmovieimplementation.ui.base.BaseFragment
import id.cahyowhy.tmdbmovieimplementation.ui.base.BaseViewItem
import id.cahyowhy.tmdbmovieimplementation.ui.util.ext.observe
import org.koin.android.viewmodel.ext.android.viewModel
open class MovieFragment(
private val movieListType: MovieListType
) : BaseFragment() {
private val viewModel by viewModel<MovieFragmentViewModel>()
private lateinit var binding: MoviesFragmentResultBinding
private val movieAdapter by lazy {
VisitableRecyclerAdapter(
ItemTypeFactoryImpl(),
::onItemClicked
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = MoviesFragmentResultBinding.inflate(
inflater,
container,
false
)
return binding.root
}
override fun onResume() {
super.onResume()
viewModel.loadData(0, movieListType)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
with(binding) {
recyclerView.adapter = movieAdapter
recyclerView.setHasFixedSize(true)
swipeRefresh.setOnRefreshListener { viewModel.loadData(0, movieListType) }
}
super.onViewCreated(view, savedInstanceState)
}
override fun observeChange() {
observe(viewModel.loading, ::handleLoading)
observe(viewModel.movies, ::onDataLoaded)
observe(viewModel.toastMessage, ::showSnackbarMessage)
}
private fun handleLoading(status: Boolean) {
binding.swipeRefresh.isRefreshing = status
}
private fun onDataLoaded(items: List<BaseViewItem>) {
movieAdapter.submitList(items)
}
private fun onItemClicked(viewItem: BaseViewItem, view: View) {
when (viewItem) {
is MovieItem -> {
Log.d("MovieItem", "MovieItem Click: ${viewItem.title}")
}
is ErrorStateItem -> {
viewModel.loadData(0, movieListType)
}
}
}
companion object {
fun newInstance(movieListType: MovieListType): MovieFragment =
MovieFragment(movieListType)
}
}
这是我从 MainActivity.kt
打来的电话
class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding;
....
fun initView() {
with(binding) {
viewPager.adapter = MyPagerAdapter(supportFragmentManager)
viewPagerTab.setupWithViewPager(viewPager)
}
}
谁能解决这个问题..谢谢..
问题是 MyFragment
是一个 class 而 FragmentManager
是你通过调用 supportFragmentManager
得到的东西。这是系统提供给你的。为了让片段管理器能够将新的片段添加到返回堆栈,提供给它的片段应该是唯一的。
现在我不知道您的用例是什么,但是调用 MyFragment.newInstance()
不会为您提供唯一的 classes,因为它们只是相同 MyFragment
[=33] 的新实例=].错误日志指出。
为了解决这个问题,您可以创建三个不同的片段 class,例如 PopularMoviesFragment
、TopRatedMoviesFragment
和 UpcomingMoviesFragment
,然后将它们添加到您在适配器上的列表中 class.
我知道这似乎需要做很多工作,但这样您就有了三个不同的片段,显示了三种不同电影案例的数据,并且您可以在其中添加额外的逻辑。而且你也不会遇到 java.lang.IllegalStateException: Fragment already added: MovieFragment
错误
您调用的适配器代码:
private val pages = listOf(
MovieFragment.newInstance(MovieListType.POPULAR),
MovieFragment.newInstance(MovieListType.TOP_RATED),
MovieFragment.newInstance(MovieListType.UPCOMING)
)
现在应该看起来像:
private val pages = listOf(
PopularMoviesFragment.newInstance(MovieListType.POPULAR),
TopRatedMoviesFragment.newInstance(MovieListType.TOP_RATED),
UpcomingMoviesFragment.newInstance(MovieListType.UPCOMING)
)
在我的 MyPagerAdapter class 上添加了错误片段,它扩展了 FragmentPagerAdapter
这是我的错误日志
E/AndroidRuntime: FATAL EXCEPTION: main
Process: id.cahyowhy.tmdbmovieimplementation, PID: 8228
java.lang.IllegalStateException: Fragment already added: MovieFragment{df79747} (01cf33b8-9eb3-4dce-9519-384ca7dd7570) id=0x7f08014e android:switcher:2131231054:0}
at androidx.fragment.app.FragmentStore.addFragment(FragmentStore.java:67)
at androidx.fragment.app.FragmentManager.addFragment(FragmentManager.java:1563)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:405)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
at androidx.fragment.app.FragmentManager.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
这是我的 pageradapter 代码
class MyPagerAdapter(fm: FragmentManager) :
FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val pages = listOf(
MovieFragment.newInstance(MovieListType.POPULAR),
MovieFragment.newInstance(MovieListType.TOP_RATED),
MovieFragment.newInstance(MovieListType.UPCOMING)
)
override fun getItem(position: Int): Fragment {
return pages[position]
}
override fun getCount(): Int {
return pages.size
}
override fun getPageTitle(position: Int): CharSequence? {
return when (position) {
0 -> "Popular"
1 -> "Top Rated"
else -> "Up Coming"
}
}
}
这是我的电影片段代码
package id.cahyowhy.tmdbmovieimplementation.ui.activity.fragment
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import id.cahyowhy.tmdbmovieimplementation.databinding.MoviesFragmentResultBinding
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.ItemTypeFactoryImpl
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.VisitableRecyclerAdapter
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.viewholder.ErrorStateItem
import id.cahyowhy.tmdbmovieimplementation.ui.adapter.viewholder.MovieItem
import id.cahyowhy.tmdbmovieimplementation.ui.base.BaseFragment
import id.cahyowhy.tmdbmovieimplementation.ui.base.BaseViewItem
import id.cahyowhy.tmdbmovieimplementation.ui.util.ext.observe
import org.koin.android.viewmodel.ext.android.viewModel
open class MovieFragment(
private val movieListType: MovieListType
) : BaseFragment() {
private val viewModel by viewModel<MovieFragmentViewModel>()
private lateinit var binding: MoviesFragmentResultBinding
private val movieAdapter by lazy {
VisitableRecyclerAdapter(
ItemTypeFactoryImpl(),
::onItemClicked
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = MoviesFragmentResultBinding.inflate(
inflater,
container,
false
)
return binding.root
}
override fun onResume() {
super.onResume()
viewModel.loadData(0, movieListType)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
with(binding) {
recyclerView.adapter = movieAdapter
recyclerView.setHasFixedSize(true)
swipeRefresh.setOnRefreshListener { viewModel.loadData(0, movieListType) }
}
super.onViewCreated(view, savedInstanceState)
}
override fun observeChange() {
observe(viewModel.loading, ::handleLoading)
observe(viewModel.movies, ::onDataLoaded)
observe(viewModel.toastMessage, ::showSnackbarMessage)
}
private fun handleLoading(status: Boolean) {
binding.swipeRefresh.isRefreshing = status
}
private fun onDataLoaded(items: List<BaseViewItem>) {
movieAdapter.submitList(items)
}
private fun onItemClicked(viewItem: BaseViewItem, view: View) {
when (viewItem) {
is MovieItem -> {
Log.d("MovieItem", "MovieItem Click: ${viewItem.title}")
}
is ErrorStateItem -> {
viewModel.loadData(0, movieListType)
}
}
}
companion object {
fun newInstance(movieListType: MovieListType): MovieFragment =
MovieFragment(movieListType)
}
}
这是我从 MainActivity.kt
打来的电话class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding;
....
fun initView() {
with(binding) {
viewPager.adapter = MyPagerAdapter(supportFragmentManager)
viewPagerTab.setupWithViewPager(viewPager)
}
}
谁能解决这个问题..谢谢..
问题是 MyFragment
是一个 class 而 FragmentManager
是你通过调用 supportFragmentManager
得到的东西。这是系统提供给你的。为了让片段管理器能够将新的片段添加到返回堆栈,提供给它的片段应该是唯一的。
现在我不知道您的用例是什么,但是调用 MyFragment.newInstance()
不会为您提供唯一的 classes,因为它们只是相同 MyFragment
[=33] 的新实例=].错误日志指出。
为了解决这个问题,您可以创建三个不同的片段 class,例如 PopularMoviesFragment
、TopRatedMoviesFragment
和 UpcomingMoviesFragment
,然后将它们添加到您在适配器上的列表中 class.
我知道这似乎需要做很多工作,但这样您就有了三个不同的片段,显示了三种不同电影案例的数据,并且您可以在其中添加额外的逻辑。而且你也不会遇到 java.lang.IllegalStateException: Fragment already added: MovieFragment
错误
您调用的适配器代码:
private val pages = listOf(
MovieFragment.newInstance(MovieListType.POPULAR),
MovieFragment.newInstance(MovieListType.TOP_RATED),
MovieFragment.newInstance(MovieListType.UPCOMING)
)
现在应该看起来像:
private val pages = listOf(
PopularMoviesFragment.newInstance(MovieListType.POPULAR),
TopRatedMoviesFragment.newInstance(MovieListType.TOP_RATED),
UpcomingMoviesFragment.newInstance(MovieListType.UPCOMING)
)