2

I am using ViewPager2 with FragmentStateAdapter and I am setting offscreenPageLimit to 1. Each Fragment contains a surface (obtained via a TextureView) to be drawn on.

The code is fairly simple:

package com.example.testapplication

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.SurfaceTexture
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.item_fragment.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val pageAdapter = object: FragmentStateAdapter(this) {
            override fun createFragment(position: Int): Fragment {
                return ItemFragment.create(position)
            }

            override fun getItemCount(): Int = 100
        }

        val viewpager = findViewById<ViewPager2>(R.id.viewpager).apply {
            offscreenPageLimit = 1
            adapter = pageAdapter
        }

        viewpager.currentItem = 0
    }


    class ItemFragment: Fragment() {
        private var position: Int = 0

        companion object {
            private val ARG = ItemFragment::class.java.name+"_arg"
            fun create(position: Int): ItemFragment {
                return ItemFragment().also {
                    it.arguments = Bundle().apply {
                        putInt(ARG, position)
                    }
                }
            }
        }

        private val TAG: String
            get() = "Fragment_${position}"

        override fun onAttach(context: Context) {
            super.onAttach(context)
            position = arguments!!.getInt(ARG, 0)
            Log.d(TAG, "onAttach")
        }

        override fun onDetach() {
            super.onDetach()
            Log.d(TAG, "onDetach")
        }

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            Log.d(TAG, "onCreate")
        }

        override fun onStart() {
            super.onStart()
            Log.d(TAG, "onStart")
        }

        override fun onResume() {
            super.onResume()
            Log.d(TAG, "onResume")
        }

        override fun onPause() {
            super.onPause()
            Log.d(TAG, "onPause")
        }

        override fun onStop() {
            super.onStop()
            Log.d(TAG, "onStop")
        }

        override fun onDestroy() {
            super.onDestroy()
            Log.d(TAG, "onDestroy")
        }

        @SuppressLint("InflateParams")
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            Log.d(TAG, "onCreateView")
            return inflater.inflate(R.layout.item_fragment, null)
        }

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            textview.text = position.toString()
            textureview.surfaceTextureListener = object: TextureView.SurfaceTextureListener {
                override fun onSurfaceTextureSizeChanged(
                    surface: SurfaceTexture?,
                    width: Int,
                    height: Int
                ) {
                }

                override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
                }

                override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
                    Log.d(TAG, "onSurfaceTextureDestroyed")
                    return true
                }

                override fun onSurfaceTextureAvailable(
                    surfaceTexture: SurfaceTexture?,
                    width: Int,
                    height: Int
                ) {
                    Log.d(TAG, "onSurfaceTextureAvailable")
                    val surface = Surface(surfaceTexture)
                    val canvas = surface.lockCanvas(null)
                    canvas.drawColor(Color.CYAN)
                    surface.unlockCanvasAndPost(canvas)
                    surface.release()
                }
            }
        }

        override fun onDestroyView() {
            super.onDestroyView()
            Log.d(TAG, "onDestroyView")
        }

    }

}

And the layout is as following:

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

item_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextureView
        android:id="@+id/textureview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

The off-screen fragments are created as expected. However, the destroy behavior is not what I am expecting. You can see fragment0 is not destroyed until I scrolled to fragment4. But surface on fragment0 got destroyed when I scrolled to fragment2.

04-21 17:51:20.527 20921 20921 D Fragment_0: onAttach
04-21 17:51:20.527 20921 20921 D Fragment_0: onCreate
04-21 17:51:20.527 20921 20921 D Fragment_0: onCreateView
04-21 17:51:20.531 20921 20921 D Fragment_0: onStart
04-21 17:51:20.531 20921 20921 D Fragment_0: onResume
04-21 17:51:20.533 20921 20921 D Fragment_1: onAttach
04-21 17:51:20.533 20921 20921 D Fragment_1: onCreate
04-21 17:51:20.534 20921 20921 D Fragment_1: onCreateView
04-21 17:51:20.536 20921 20921 D Fragment_1: onStart
04-21 17:51:20.540 20921 20921 D Fragment_0: onSurfaceTextureAvailable
04-21 17:51:20.544 20921 20921 D Fragment_1: onSurfaceTextureAvailable
04-21 17:51:22.082 20921 20921 D Fragment_2: onAttach
04-21 17:51:22.083 20921 20921 D Fragment_2: onCreate
04-21 17:51:22.083 20921 20921 D Fragment_2: onCreateView
04-21 17:51:22.087 20921 20921 D Fragment_2: onStart
04-21 17:51:22.428 20921 20921 D Fragment_0: onPause
04-21 17:51:22.428 20921 20921 D Fragment_1: onResume
04-21 17:51:22.430 20921 20921 D Fragment_2: onSurfaceTextureAvailable
04-21 17:51:23.342 20921 20921 D Fragment_3: onAttach
04-21 17:51:23.342 20921 20921 D Fragment_3: onCreate
04-21 17:51:23.342 20921 20921 D Fragment_3: onCreateView
04-21 17:51:23.348 20921 20921 D Fragment_3: onStart
04-21 17:51:23.690 20921 20921 D Fragment_0: onSurfaceTextureDestroyed
04-21 17:51:23.691 20921 20921 D Fragment_1: onPause
04-21 17:51:23.691 20921 20921 D Fragment_2: onResume
04-21 17:51:23.693 20921 20921 D Fragment_3: onSurfaceTextureAvailable
04-21 17:51:24.452 20921 20921 D Fragment_4: onAttach
04-21 17:51:24.453 20921 20921 D Fragment_4: onCreate
04-21 17:51:24.453 20921 20921 D Fragment_4: onCreateView
04-21 17:51:24.456 20921 20921 D Fragment_4: onStart
04-21 17:51:24.796 20921 20921 D Fragment_1: onSurfaceTextureDestroyed
04-21 17:51:24.798 20921 20921 D Fragment_2: onPause
04-21 17:51:24.798 20921 20921 D Fragment_3: onResume
04-21 17:51:24.799 20921 20921 D Fragment_4: onSurfaceTextureAvailable
04-21 17:51:28.500 20921 20921 D Fragment_5: onAttach
04-21 17:51:28.500 20921 20921 D Fragment_5: onCreate
04-21 17:51:28.501 20921 20921 D Fragment_5: onCreateView
04-21 17:51:28.506 20921 20921 D Fragment_5: onStart
04-21 17:51:28.853 20921 20921 D Fragment_2: onSurfaceTextureDestroyed
04-21 17:51:28.855 20921 20921 D Fragment_0: onStop
04-21 17:51:28.855 20921 20921 D Fragment_0: onDestroyView
04-21 17:51:28.856 20921 20921 D Fragment_0: onDestroy
04-21 17:51:28.856 20921 20921 D Fragment_0: onDetach
04-21 17:51:28.857 20921 20921 D Fragment_3: onPause
04-21 17:51:28.857 20921 20921 D Fragment_4: onResume
04-21 17:51:28.858 20921 20921 D Fragment_5: onSurfaceTextureAvailable

This is very annoying since the fragment and its surface are not destroyed at the same time. Does anyone have an idea on what is going wrong here?

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
Robin
  • 10,052
  • 6
  • 31
  • 52
  • This seems like a bug to me. I've created a report for this in IssueTracker [here](https://issuetracker.google.com/issues/171180138). – Adil Hussain Oct 19 '20 at 17:38

0 Answers0