Android开发view

(译)Fragment 1.2 新特性

2019-11-04  本文已影响0人  于卫国

本文译自AndroidDevSummit 2019: What's new in Android Fragments,介绍了Fragment 1.2版本中引入的FragmentContainerView和FragmentFactory的使用。

本文首发:http://yuweiguocn.github.io/

《过零丁洋》
辛苦遭逢起一经,干戈寥落四周星。
山河破碎风飘絮,身世浮沉雨打萍。
惶恐滩头说惶恐,零丁洋里叹零丁。
人生自古谁无死?留取丹心照汗青。
-宋代,文天祥

新特性

在2019 AndroidDevSummit上我注意到的一件事情是发布了androidx.fragment:1.2.0-rc01。这个是当前release版本的候选,这个版本包含一些更容易处理fragment的新的API。

在本文中,我们来学习一下这个版本中新添加的两个API。FragmentContainerView是一个应该被用于fragment的宿主的新View,它替换了通常使用的FrameLayout。还有一个FragmentFactory用于自定义fragment如何被创建。

FragmentContainerView vs FrameLayout

在activity中使用FrameLayout作为fragment的宿主是一个很常见的模板。在Android社区中已经这么做了很多年但这马上将会改变。androidx团队引入了名为FragmentContainerView的View处理这个事情。

<androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

你所需要做的就是使用FragmentContainerView替换FrameLayout并且一切都会开箱即用,对于你处理的fragment transactions什么都不需要修改。译者注:FragmentContainerView继承自FrameLayout,但只允许添加fragment view。

它带来的好处是改进了对fragment z-ordering的处理。这个是他们使用是例子,这意味着两个fragment之前的退出和进入过渡不会互相重叠。使用FragmentContainerView将先开启退出动画然后才是进入动画。

如果你问这个能否代替<fragment>标签?答案是可以的。你需要做的是添加android:name="your_class_name",它会使用FragmentTransaction构建显示你的fragment。这意味着稍候你可以使用fragment transactions替换它。

<androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container"
        android:name="com.company.FragmentClass"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

FragmentFactory

对于创建一个Fragment最常见的建议是让你的fragment保留一个无参的构造方法。直到现在,Android框架需要这个无参构造方法实例化你的fragment。FragmentFactory的到来改变了这一现状。它可以让你控制怎样构建fragment,这意味着你可以在fragment中使用构造函数依赖注入。

你需要做的是继承FragmentFactory并提供你的自定义实现,然后告诉fragment manager构建fragment时使用这个factory。

// Your custom fragment factory
class MyFragmentFactory (
    private val exampleService: ExampleService
) : FragmentFactory() {

    override fun instantiate(classLoader: ClassLoader, className: String): Fragment { ... }

}

// Your Activity
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var fragmentFactory: MyFragmentFactory

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

还有就是Android社区习惯创建fragment的实例然后传递它到fragment transaction。

supportFragmentManager
            .beginTransaction()
            .replace(R.id.fragment_container, SecondFragment())
            .commit()

在这个新版本中,FragmentTransaction有一些新的重载允许你传递Class<Fragment>,然后它会被传递到FragmentFactory创建fragment的实例。因此上面例子的代码会变得像这样。

supportFragmentManager.beginTransaction()
                .replace(R.id.fragment_container, SecondFragment::class.java, args = null)
                .commit()

使用FragmentScenario测试fragment

我们都有依赖Dagger获取依赖的fragment。现在使用FragmentFactory可以很容易使用构造函数注入替换Dagger注入。这也让测试这些fragment变得容易,不用担心通过dagger注入mocks。

androidx.fragment:fragment-testing也进行了更新允许你在测试时提供factory构建fragment。这意味着你可以在fragment中使用假的factory通过构造函数注入假依赖。这个是例子:

val scenario = launchFragmentInContainer<FirstFragment>(factory = MockFactory())
        // Your test action
        scenario.onFragment { fragment ->
            // Your test assertions

        }

总结

新发布的androidx.fragment对于简化fragment的使用迈出了很大一步。至少对我来说易于配置和测试是很友好的改变,我也希望你找到对你有用的。

对于本版本中包含的所有更改请参考官方发版文档

如果你想测试这些在build.gradle添加依赖:

  def fragment_version = "1.2.0-rc01"
  implementation "androidx.fragment:fragment-ktx:$fragment_version"
  implementation "androidx.fragment:fragment-testing:$fragment_version"
上一篇下一篇

猜你喜欢

热点阅读