Search code examples
androidkotlinandroid-viewpager

Why is my Viewpager not showing any fragments after opening the second time and why can childfragmentmanager not be used?


I have a Fragment (InnerFragment) placed inside a Viewpager (MainViewPager).

This Fragment (InnerFragment) does also contain a ViewPager (NestedViewPager) with multiple Fragments. When I swipe or open the InnerFragment everything works fine and the NestedViewPager shows all Fragments the way it should.

When I leave the InnerFragment after swiping the MainViewPager and go back to the InnerFragment it is blank and nothing shows up.

One solution as described in the internet is using the childfragmentmanager. Unfortunately this doesn't work because if I do so following exception is thrown.

java.lang.IllegalStateException: Fragment ProductImageFragment{c458f99 (1213d869-3715-4541-8nab-f87cyc350630) id=0x8f093165 android:switcher:2111xxxxxx:0} declared target fragment ProductImagesFragment{4b4f25e (99a6aaf6-5500-4821-902f-7bf30f87554c) id=0x7f090126 android:switcher:2131296550:2} that does not belong to this FragmentManager!
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:805)

Maybe it is also important to note, that the MainFragment is implementing an Interface of the Innerfragment.

MainFragment

class ProductImagesFragment : Fragment(),
    ProductImageFragment.IProductImageHandler,
    ProductImageUploadDialog.ProductImageUploadDialogEventListener {

    private lateinit var viewPager: ViewPager

    interface IProductImageUploadHandler{
        fun onImageUploadToServerFinished(bitmap: Bitmap, imageData: ProductImage)
    }

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
    }
   

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
    {
        return layoutInflater.inflate(R.layout.fragment_product_images,container,false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewPager = view.findViewById(R.id.viewPagerImages)
        setViewPagerAdapter()
    }

    private fun setViewPagerAdapter(){
        val manager = fragmentManager
        if(manager!=null){
            viewPager.adapter = product?.let {product ->
                ImageAdapter(this,
                    product,productImageList,manager)
            }
        }
    }

class ImageAdapter(private val productImagesFragment: ProductImagesFragment, private val product: Product, private val imagesList:ArrayList<ProductImage>, fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {

        override fun getCount(): Int {
            return imagesList.size
        }

        override fun getItem(position: Int): Fragment {
            val fragment = ProductImageFragment()
            val bundle = Bundle()
            val image = imagesList[position]
            bundle.putInt("productId",product.id)
            bundle.putParcelable("productImage",image)
            bundle.putInt("maxImages",imagesList.size)
            fragment.setTargetFragment(productImagesFragment,1)
            fragment.arguments = bundle
            return fragment
        }
    }


}

InnerFragment

class ProductImageFragment : Fragment() {

    private lateinit var productImageHandler: IProductImageHandler

    interface IProductImageHandler{
        fun onImageDeleted(id: Int)
        fun onOrderChanged(url: String, newValue: Int, oldValue: Int)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            productImageHandler = targetFragment as IProductImageHandler
        }catch (exception: Exception){
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_product_image, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       
    }

    private fun setValues(view: View){
        
    }
}


Solution

  • You must use the childFragmentManager in order for the state to be restored properly.

    You shouldn't be using the target fragment API at all. In fact, if you're using the childFragmentManager, your child fragments already have a reference to the parent via requireParentFragment() - just use that instead of targetFragment.

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
             productImageHandler = requireParentFragment() as IProductImageHandler
        }catch (exception: Exception){
        }
    }