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,例如 PopularMoviesFragmentTopRatedMoviesFragmentUpcomingMoviesFragment,然后将它们添加到您在适配器上的列表中 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)
    )