preface

  • Android Fragments: FragmentFactory
  • The original address: proandroiddev.com/fragmentfac…
  • Husayn Hakeem

The new Fragment feature “New ways to transfer data between Fragments” and source code analysis have just been published in the previous article. Several important apis have been added to Fragment 1.3.0.

Pick up where you left off with FragmentFactory and FragmentContainerView and how to use them with Koin. This is an important update Google made to Fragment 1.2.0

Through this passage you will learn the following, which will be answered in the thinking section of the translator

  • What is FragmentFactory?
  • When is FragmentFactory used?
  • What is FragmentContainerView?
  • Why does Google strongly recommend FragmentContainerView?
  • How does Koin work with FragmentFactory and partial source code analysis?
  • How to handle nested Fragments?

This article covers a lot of important new points, with your own understanding, please read on patiently, should be able to learn a lot of skills.

The translation

We can now use FragmentFactory to inject Fragment constructors, but this is not a mandatory API for developers, and in some cases it can be considered a good design method to test fragments with external dependencies.

This article will explain what a FragmentFactory is, when and how to use it, and how to handle nested fragments.

What is FragmentFactory?

Previous instances of the Fragment were instantiated using the default empty constructor. This is because the system needs to reinitialize it in certain situations, such as configuration changes or App process rebuilds. Without the limitations of the default constructor, the system does not know how to reinitialize the Fragment instance.

The FragmentFactory appears to address this limitation by helping systems create Fragment instances by providing it with the parameters/dependencies needed to instantiate the Fragment.

How do I use FragmentFactory?

If your Fragment doesn’t have an empty constructor, you need to create a FragmentFactory to handle initialization of it, by inheriting FragmentFactory and overriding FragmentFactory#instantiate().

class CustomFragmentFactory(private val dependency: Dependency) : FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
        if (className == CustomFragment::class.java.name) {
            return CustomFragment(dependency)
        }
        return super.instantiate(classLoader, className)
    }
}
Copy the code

Fragments are managed by FragmentManagers, so in order to use the FragmentFactory you need to associate with the FragmentManager, More specifically, it must be assigned to the FragmentManager that contains the Fragment component, which can be an Activity or Fragment.

When do FragmentFactory and FragmentManager associate

The FragmentFactory is responsible for initializing the Fragment on both the Activity and parent Fragment, so you should set it before creating the Fragment.

  • Before creating Component’s View: If you define a Fragment in XML, you should use the Fragment tag<fragment>Or FragmentContainerView.
  • Before creating a Fragment: Use FragmentTransaction if the Fragment is added dynamically.
  • Before the System restores the Fragment: If the Fragment is rebuilt because of configuration changes or App process rebuilding.

With these restrictions, you can associate the FragmentFactory and FragmentManager before Activity#onCreate() and Fragment#onCreate(), The Fragment is reinitialized before the view is created at both calls.

This means that the FragmentFactory and FragmentManager should be associated before super#onCreate().

  • Associate the FragmentFactory and FragmentManager with the Activity
class HostActivity : AppCompatActivity() { private val customFragmentFactory = CustomFragmentFactory(Dependency()) override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = customFragmentFactory super.onCreate(savedInstanceState) // ... }}Copy the code
  • Associate FragmentFactory and FragmentManager in fragments
class ParentFragment : Fragment() { private val customFragmentFactory = CustomFragmentFactory(Dependency()) override fun onCreate(savedInstanceState: Bundle?) { childFragmentManager.fragmentFactory = customFragmentFactory super.onCreate(savedInstanceState) // ... }}Copy the code

Do YOU want to use FragmentFactory?

By now, you might have created fragments using their default constructors, then injected the dependencies they needed with a library like Dagger or Koin, or initialized them in the Fragment before they were used.

If your Fragment has an empty constructor by default, you don’t need to use FragmentFactory. If you accept arguments in the Fragment constructor, you must use FragmentFactory. Or sell fragments. InstantiationException anomalies

How to use both Fragment and FragmentFactory?

Just set the FragmentFactory before creating a Fragment, and it will be used for instantiation. This means using a custom FragmentFactory before adding Fragments.

  • Static add:Use the Fragment tag<fragment>And FragmentContainerView.
<? The XML version = "1.0" encoding = "utf-8"? > <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/customFragment" android:name="com.example.CustomFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:tag="custom_fragment" />Copy the code

Set FragmentFactory to initialize the FragmentContainerView declared on the Fragment

class HostActivity : AppCompatActivity() {
    private val customFragmentFactory = CustomFragmentFactory(Dependency())

    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager.fragmentFactory = customFragmentFactory
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_with_fragment_container_view)
    }
}
Copy the code
  • Dynamic add: add a Fragment dynamically using the FragmentTransaction#add() method
class HostActivity : AppCompatActivity() {
    private val customFragmentFactory = CustomFragmentFactory(Dependency())

    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager.fragmentFactory = customFragmentFactory
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_with_empty_frame_layout)
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .add(R.id.content, CustomFragment::class.java, arguments)
                .commit()
        }
    }
}
Copy the code

FragmentFactory and nested fragments

If a parent Fragment contains nested fragments or multi-level nested fragments, they all use the same FragmentFactory as the parent Fragment. Nested fragments needs to call Fragment# childFragmentManager fragmentFactory

class ParentFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { childFragmentManager.fragmentFactory = parentFragmentFactory super.onCreate(savedInstanceState) if (savedInstanceState  == null) { // Add NestedFragment } } } class NestedFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { childFragmentManager.fragmentFactory = childFragmentFactory super.onCreate(savedInstanceState) if (savedInstanceState == null) { // Add NestedNestedFragment } } } class NestedNestedFragment : Fragment()Copy the code

The translator think

Let’s summarize some of the most important updates to Fragment and when they can be used:

  • Previous instances of Fragments were instantiated using the default empty constructor, and FragmentFactory was created to address this limitation.
  • FragmentFactory is not required. If you accept arguments in the Fragment constructor, you must use the FragmentFactory
  • The FragmentFactory needs to be used in an Activity or Fragment, and it needs to be associated with the FragmentManager before Activity#onCreate() and Fragment#onCreate()
  • Nested fragments, or multi-level nested fragments, use the same FragmentFactory
  • Because of FragmentFactory, you can pass parameters in the Fragment constructor, which means you can use frameworks like Koin to implement constructor dependency injection, which I’ll show you how to do later. Okay

Let’s take a look at what FragmentContainerView is and why Google strongly recommends using the FragmentContainerView container to store dynamically added fragments.

What is FragmentContainerView? Why does Google strongly recommend it?

Let’s take a look at Google’s update:

FragmentContainerView: FragmentContainerView is a custom View that inherits FrameLayout. Unlike ViewGroups, FragmentContainerView accepts only Fragment Views.

Why does Google strongly recommend it?

In Google Issue I asked a question about a fragment z-ordering, which means that entering and exiting the fragment animation will cause a problem. The entering fragment will be underneath the exiting fragment until it is completely off the screen. This will result in incorrect animations when switching between fragments.

The advantage of using FragmentContainerView is the improved handling of fragment z-ordering. This is an example of a Google demo that optimizes the exit and entry transitions of two Fragments so that they don’t overlap. Using FragmentContainerView will enable the exit animation first and then the entry animation.

How does Koin work with FragmentFactory and source code analysis

[2.4K Start] Abandon Dagger Hug Koin analysis of Koin performance, if you have not seen it, it is suggested to check it out.

The Koin team started supporting Fragment dependency injection in version 2.1.0, as shown in the screenshot below:

1. Add Koin Fragment dependencies

Implementation "org. Koin: koin androidx - fragments: 2.1.5." "Copy the code

2. Create Fragment and pass the ViewModel

class FragmentTest(val mainViewModel: MainViewModel) : Fragment(){
    ......
}
Copy the code

3. Create Fragment Modules

val viewModelsModule = module {
    viewModel { MainViewModel() }
}

val fragmentModules = module {
    fragment { FragmentTest(get()) }
}

val appModules = listOf(fragmentModules, viewModelsModule)
Copy the code

4. Set KoinFragmentFactory when the startKoin method is called

startKoin {
    AndroidLogger(Level.DEBUG)
    androidContext(this@App)
    fragmentFactory()
    loadKoinModules(appModules)
}
Copy the code

FragmentFactory is an extension function of KoinApplication, providing KoinFragmentFactory code as follows:

koin.loadModules(listOf(module {
        single<FragmentFactory> { KoinFragmentFactory() }
    }))
}
Copy the code

KoinFragmentFactory internal source code

class KoinFragmentFactory(val scope: Scope? = null) : FragmentFactory(), KoinComponent { override fun instantiate(classLoader: ClassLoader, className: String): Fragment { val clazz = Class.forName(className).kotlin val instance = if (scope ! = null) { scope.getOrNull<Fragment>(clazz) }else{ getKoin().getOrNull<Fragment>(clazz) } return instance ? : super.instantiate(classLoader, className) } }Copy the code

Inherits FragmentFactory and overrides the FragmentFactory#instantiate() method, where we get the Fragment with className as an argument, And try to retrieve the Fragment instance from Koin

5. Call the setupKoinFragmentFactory binding before the onCreate method

override fun onCreate(savedInstanceState: Bundle?) {
    setupKoinFragmentFactory()
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}
Copy the code

6. Add the Fragment and pass the Bundle

val arguments = Bundle().apply { putString(FragmentTest.KEY_NAME, "From MainActivity")} supportFragmentManager. BeginTransaction (). The replace (R.i, dc ontainer, FragmentTest: : class. Java, arguments) .commit()Copy the code

The source code has been uploaded to JDataBinding, and you can view the App, MainActivity, AppModule, and FragmentTest classes

reference

  • Github.com/InsertKoinI…
  • Android Fragments: FragmentFactory
  • Developer.android.com/jetpack/and…

conclusion

Committed to sharing a series of Android system source code, reverse analysis, algorithm, translation related articles, is currently translating a series of European and American selected articles, please continue to pay attention to, in addition to translation and thinking about each European and American article, if it is helpful to you, please help me a like, thank you!! Looking forward to growing up with you.

Plan to establish a most complete and latest AndroidX Jetpack related components of the actual combat project and related components of the principle of analysis articles, currently has included App Startup, Paging3, Hilt and so on, is gradually adding other Jetpack new members, the warehouse continues to update, Check it out: AndroidX-Jetpack-Practice, please give me a thumbs up if this repository is helpful to you, and I will continue to complete more project practices for new members of Jetpack.

algorithm

Since LeetCode has a large question bank, hundreds of questions can be selected for each category. Due to the limited energy of each person, it is impossible to brush all the questions. Therefore, I sorted the questions according to the classic types and the difficulty of the questions.

  • Data structures: arrays, stacks, queues, strings, linked lists, trees…
  • Algorithms: Search algorithm, search algorithm, bit operation, sorting, mathematics,…

Each problem will be implemented in Java and Kotlin, and each problem has its own solution ideas, time complexity and space complexity. If you like algorithms and LeetCode like me, you can pay attention to my LeetCode problem solution on GitHub: Leetcode-Solutions-with-Java-And-Kotlin, come to learn together And look forward to growing with you.

Android 10 source code series

  • How is APK generated
  • APK installation process
  • 0xA03 Android 10 source code analysis: APK loading process of resource loading
  • Android 10 source code: APK
  • Dialog loading and drawing process and use in Kotlin, DataBinding
  • WindowManager View binding and architecture

Android Apps

  • How to get video screenshots efficiently
  • How to package Kotlin + Android Databinding in your project
  • [Google engineers] just released a new Fragment feature, “New ways to transfer Data between Fragments” and source code analysis
  • [2.4K Start] Drop Dagger to Koin
  • [5K +] Kotlin’s performance optimization stuff

Tool series

  • Shortcuts to AndroidStudio that few people know
  • Shortcuts to AndroidStudio that few people know
  • All you need to know about ADB commands
  • 10 minutes introduction to Shell scripting

The reverse series

  • Dynamically debug APP based on Smali file Android Studio
  • The Android Device Monitor tool cannot be found in Android Studio 3.2