FragmentLifecycleCallbacks

Halo! Hari ini saya terus berbicara tentang alat yang karena beberapa alasan telah kehilangan perhatian. Dalam artikel saya sebelumnya saya menulis tentang kemungkinan ActivityLifecycleCallbacks dan bagaimana mereka dapat digunakan tidak hanya untuk mencatat siklus hidup. Namun selain Kegiatan, ada juga Fragmen, dan kami ingin mendapatkan perilaku serupa untuk mereka.


Tanpa ragu, saya membuka pencarian untuk kelas di AndroidStudio (Cmd / Ctrl + O) dan memasukkan FragmentLifecycleCallbacks di sana. Dan apa yang mengejutkan saya ketika pencarian menunjukkan saya FragmentManager.FragmentLifecycleCallbacks. Pembaca yang paling tidak sabar menulis tentang ini di komentar, jadi di sini adalah kelanjutan dari keseluruhan cerita. Sebaliknya, di bawah luka!



Apa itu


Antarmuka seperti ActivityLifecycleCallbacks, hanya untuk Fragmen.


FragmentLifecycleCallbacks
/**
 * Callback interface for listening to fragment state changes that happen
 * within a given FragmentManager.
 */
public abstract static class FragmentLifecycleCallbacks {
    /**
     * Called right before the fragment's {@link Fragment#onAttach(Context)} method is called.
     * This is a good time to inject any required dependencies or perform other configuration
     * for the fragment before any of the fragment's lifecycle methods are invoked.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     * @param context Context that the Fragment is being attached to
     */
    public void onFragmentPreAttached(
        @NonNull FragmentManager fm, 
        @NonNull Fragment f,
        @NonNull Context context) {}

    /**
     * Called after the fragment has been attached to its host. Its host will have had
     * `onAttachFragment` called before this call happens.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     * @param context Context that the Fragment was attached to
     */
    public void onFragmentAttached(
        @NonNull FragmentManager fm,
        @NonNull Fragment f,
        @NonNull Context context) {}

    /**
     * Called right before the fragment's {@link Fragment#onCreate(Bundle)} method is called.
     * This is a good time to inject any required dependencies or perform other configuration
     * for the fragment.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     * @param savedInstanceState Saved instance bundle from a previous instance
     */
    public void onFragmentPreCreated(
        @NonNull FragmentManager fm,
        @NonNull Fragment f,
        @Nullable Bundle savedInstanceState) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onCreate(Bundle)}. This will only happen once for any given
     * fragment instance, though the fragment may be attached and detached multiple times.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     * @param savedInstanceState Saved instance bundle from a previous instance
     */
    public void onFragmentCreated(
        @NonNull FragmentManager fm,
        @NonNull Fragment f,
        @Nullable Bundle savedInstanceState) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onActivityCreated(Bundle)}. This will only happen once for any given
     * fragment instance, though the fragment may be attached and detached multiple times.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     * @param savedInstanceState Saved instance bundle from a previous instance
     */
    public void onFragmentActivityCreated(
        @NonNull FragmentManager fm,
        @NonNull Fragment f,
        @Nullable Bundle savedInstanceState) {}

    /**
     * Called after the fragment has returned a non-null view from the FragmentManager's
     * request to {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment that created and owns the view
     * @param v View returned by the fragment
     * @param savedInstanceState Saved instance bundle from a previous instance
     */
    public void onFragmentViewCreated(
        @NonNull FragmentManager fm,
        @NonNull Fragment f,
        @NonNull View v,
        @Nullable Bundle savedInstanceState) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onStart()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentStarted(
        @NonNull FragmentManager fm, 
        @NonNull Fragment f) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onResume()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentResumed(
        @NonNull FragmentManager fm, 
        @NonNull Fragment f) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onPause()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentPaused(
        @NonNull FragmentManager fm, 
        @NonNull Fragment f) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onStop()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentStopped(
        @NonNull FragmentManager fm,
        @NonNull Fragment f) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onSaveInstanceState(Bundle)}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     * @param outState Saved state bundle for the fragment
     */
    public void onFragmentSaveInstanceState(
        @NonNull FragmentManager fm,
        @NonNull Fragment f,
        @NonNull Bundle outState) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onDestroyView()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentViewDestroyed(
        @NonNull FragmentManager fm,
        @NonNull Fragment f) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onDestroy()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentDestroyed(
        @NonNull FragmentManager fm,
        @NonNull Fragment f) {}

    /**
     * Called after the fragment has returned from the FragmentManager's call to
     * {@link Fragment#onDetach()}.
     *
     * @param fm Host FragmentManager
     * @param f Fragment changing state
     */
    public void onFragmentDetached(
        @NonNull FragmentManager fm,
        @NonNull Fragment f) {}
}

ActivityLifecycleCallbacks Fragment, FragmentManager, . , Pre-, Fragment. , Fragment.


FragmentLifecycleCallbacks — , . , , .


— .



FragmentLifecycleCallbacks , FragmentManager. FragmentManager.registerFragmentLifecycleCallback(), : callback — recursive. , callback FragmentManager childFragmentManager’, FragmentManager' .



FragmentLifecycleCallback Activity.onCreate(), , , .


class FlcExampleActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager
            .registerFragmentLifecycleCallbacks(
                ExampleFragmentLifecycleCallback(),
                true
            )

        super.onCreate(savedInstanceState)
    }
}

class ExampleFragmentLifecycleCallback : FragmentManager.FragmentLifecycleCallbacks()

, - Activity. ActivityLifecycleCallbacks, , Activity =).


class ActivityFragmentLifecycleCallbacks :
    Application.ActivityLifecycleCallbacks,
    FragmentManager.FragmentLifecycleCallbacks() {

    override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
    ) {
        (activity as? FragmentActivity)
            ?.supportFragmentManager
            ?.registerFragmentLifecycleCallbacks(this, true)
    }
}

callback’. Activity Fragment, . , , .



dependency injection: , , Single Activity Application. , RequireCoolTool? Activity Fragment . , ? - .


Dependency injection
interface CoolTool {
    val extraInfo: String
}

class CoolToolImpl : CoolTool {
    override val extraInfo = "i am dependency"
}

interface RequireCoolTool {
    var coolTool: CoolTool
}

class InjectingLifecycleCallbacks :
    Application.ActivityLifecycleCallbacks,
    FragmentManager.FragmentLifecycleCallbacks() {

    private val coolToolImpl = CoolToolImpl()

    override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
    ) {
        (activity as? RequireCoolTool)?.coolTool = coolToolImpl
        (activity as? FragmentActivity)
            ?.supportFragmentManager
            ?.registerFragmentLifecycleCallbacks(this, true)
    }

    override fun onFragmentPreCreated(
        fm: FragmentManager,
        f: Fragment,
        savedInstanceState: Bundle?
    ) {
        (f as? RequireCoolTool)?.coolTool = coolToolImpl
    }
}

class DIActivity : AppCompatActivity(), RequireCoolTool {

    override lateinit var coolTool: CoolTool

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

        setContentView(LinearLayout {
            orientation = LinearLayout.VERTICAL
            FrameLayout {
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f)
                Text(
                    """
                    DI example activity
                    CoolTool.extraInfo="${coolTool.extraInfo}"
                    """.trimIndent()
                )
            }
            FrameLayout {
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f)
                id = R.id.container
            }
        })

        supportFragmentManager.findFragmentById(R.id.container) ?: run {
            supportFragmentManager
                .beginTransaction()
                .add(R.id.container, DIFragment())
                .commit()
        }
    }
}

class DIFragment : Fragment(), RequireCoolTool {

    override lateinit var coolTool: CoolTool

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? =
        inflater.context.FrameLayout {
            setBackgroundColor(Color.LTGRAY)
            Text(
                """
                    DI example fragment
                    CoolTool.extraInfo="${coolTool.extraInfo}"
                    """.trimIndent()
            )
        }

}

Dagger’ .


Dagger
interface DaggerTool {
    val extraInfo: String
}

class DaggerToolImpl : DaggerTool {
    override val extraInfo = "i am dependency"
}

class DaggerInjectingLifecycleCallbacks(
    val dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
) : Application.ActivityLifecycleCallbacks,
    FragmentManager.FragmentLifecycleCallbacks() {

    override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
    ) {
        dispatchingAndroidInjector.maybeInject(activity)
        (activity as? FragmentActivity)
            ?.supportFragmentManager
            ?.registerFragmentLifecycleCallbacks(this, true)
    }

    override fun onFragmentPreCreated(
        fm: FragmentManager,
        f: Fragment,
        savedInstanceState: Bundle?
    ) {
        dispatchingAndroidInjector.maybeInject(f)
    }
}

class DaggerActivity : AppCompatActivity() {

    @Inject
    lateinit var daggerTool: DaggerTool

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

        setContentView(LinearLayout {
            orientation = LinearLayout.VERTICAL
            FrameLayout {
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f)
                Text(
                    """
                    Dagger example activity
                    CoolTool.extraInfo="${daggerTool.extraInfo}"
                    """.trimIndent()
                )
            }
            FrameLayout {
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f)
                id = R.id.container
            }
        })

        supportFragmentManager.findFragmentById(R.id.container) ?: run {
            supportFragmentManager
                .beginTransaction()
                .add(R.id.container, DIFragment())
                .commit()
        }
    }
}

class DaggerFragment : Fragment() {

    @Inject
    lateinit var daggerTool: DaggerTool

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? =
        inflater.context.FrameLayout {
            Text(
                """
                Dagger example fragment
                DaggerTool.extraInfo="${daggerTool.extraInfo}"
                """.trimIndent()
            )
        }
}

@Module
class DaggerModule {
    @Provides
    fun provideDaggerTool(): DaggerTool {
        return DaggerToolImpl()
    }
}

@Module
abstract class DaggerAndroidModule {
    @ContributesAndroidInjector(modules = [DaggerModule::class])
    abstract fun contributeDaggerActivity(): DaggerActivity

    @ContributesAndroidInjector(modules = [DaggerModule::class])
    abstract fun contributeDaggerFragment(): DaggerFragment
}

, DI-, , . 


, , Activity, , .


Analytics
interface Screen {
    val screenName: String
}

interface ScreenWithParameters : Screen {
    val parameters: Map<String, String>
}

class AnalyticsCallback(
    val sendAnalytics: (String, Map<String, String>?) -> Unit
) : Application.ActivityLifecycleCallbacks, 
    FragmentManager.FragmentLifecycleCallbacks() {

    override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
    ) {
        if (savedInstanceState == null) {
            (activity as? Screen)?.screenName?.let {
                sendAnalytics(
                    it,
                    (activity as? ScreenWithParameters)?.parameters
                )
            }
        }
    }
}

class AnalyticsActivity : AppCompatActivity(), ScreenWithParameters {

    override val screenName: String = "First screen"

    override val parameters: Map<String, String> = mapOf("key" to "value")

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

        setContentView(LinearLayout {
            orientation = android.widget.LinearLayout.VERTICAL
            FrameLayout {
                layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 0, 1f)
                Text(
                    """
                    Analytics example
                    see output in Logcat by "Analytics" tag
                    """.trimIndent()
                )
            }
            FrameLayout {
                layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 0, 1f)
                id = R.id.container
            }
        })

        with(supportFragmentManager) {
            findFragmentById(R.id.container) ?: commit {
                add(R.id.container, AnalyticsFragment())
            }
        }
    }
}

class AnalyticsFragment : Fragment(), ScreenWithParameters {

    override val screenName: String = "Fragment screen"

    override val parameters: Map<String, String> = mapOf("key" to "value")

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? =
        inflater.context.FrameLayout {
            setBackgroundColor(Color.LTGRAY)
            Text(
                """
                Analytics example
                see output in Logcat by "Analytics" tag
                """.trimIndent()
            )
        }
}

?


All Articles