Fragment

490 阅读1分钟

创建Fragment

错误示例

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    supportFragmentManager.beginTransaction()
        .replace(R.id.container, NewFragment())
        .commit()
}

问题

上面的代码,当Activity被系统销毁恢复时,一个新的Fragment将会被创建。

正确示例

我们应该使用savedInstanceState == null去判断。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    if (savedInstanceState == null) {           
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, NewFragment())
            .commit()
    }
}

在onCreateView 中创建Fragment的所有对象

错误示例

private var presenter: MyPresenter? = null
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?): View? {
    presenter = MyPresenter()
    return inflater.inflate(R.layout.frag_layout, container, false)
}

问题

当Fragment被另一个容器中的Fragment替换,Fragment不会被销毁,Fragment里面的数据对象还在, 当Fragment被恢复的时候,会再次调用onCreateView,里面的数据会被重置。

0_cr0j8jzIvkTXnw8p.png

正确示例

我们应该在 onCreate 中创建Fragment所有的数据对象。

private var presenter: MyPresenter? = null
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    presenter = MyPresenter()
}

在Activity中保存Fragment

错误示例

有时候,我们为了可以调用Fragment里面的方法,通常会保存Fragment在Activity里面。

private var myFragment: MyFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    if (savedInstanceState == null) {  
        myFragment = NewFragment()
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, myFragment)
            .commit()
    }
}
private fun anotherFunction() {
    myFragemnt?.doSomething() 
}

问题

Fragment有他的生命周期,他被系统销毁,Activity里面的引用将不存在。我们需要确保不断更新对Fragment的正确引用。

正确示例

使用findFragmentByTag

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    if (savedInstanceState == null) {            
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, NewFragment(), FragmentTag)
            .commit()
    }
}
private fun anotherFunction() {
    (supportFragmentManager.findFragmentByTag(FragmentTag) as? 
        NewFragment)?.doSomething()
}

使用简单类名作为Fragment的TAG

错误示例

supportFragmentManager.beginTransaction()
    .replace(
        R.id.container, 
        fragment, 
        fragment.javaClass.simpleName)
    .commit()

问题

在 Android 中,我们使用 Proguard 或 DexGuard 模糊类名。在整个过程中,模糊的简单名称可能与其他类名发生冲突。

The danger of using getSimpleName() as TAG for Fragment

正确示例

supportFragmentManager.beginTransaction()
    .replace(
        R.id.container, 
        fragment, 
        fragment.javaClass.canonicalName)
    .commit()

参考

7 Common Mistakes Easily Made with Android Fragment