Kotlin - 创建Fragment newInstance模式的惯用方法

tri*_*iad 24 android android-fragments kotlin

Android上用于创建a的最佳实践Fragment是使用静态工厂方法并在Bundlevia中传递参数setArguments().

在Java中,这样做是这样的:

public class MyFragment extends Fragment {
    static MyFragment newInstance(int foo) {
        Bundle args = new Bundle();
        args.putInt("foo", foo);
        MyFragment fragment = new MyFragment();
        fragment.setArguments(args);
        return fragment;
    }
}
Run Code Online (Sandbox Code Playgroud)

在Kotlin,这转换为:

class MyFragment : Fragment() {
    companion object {
       fun newInstance(foo: Int): MyFragment {
            val args = Bundle()
            args.putInt("foo", foo)
            val fragment = MyFragment()
            fragment.arguments = args
            return fragment
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这对于支持与Java的互操作是有意义的,所以它仍然可以通过调用MyFragment.newInstance(...),但是如果我们不需要担心Java互操作,那么在Kotlin中是否有更惯用的方法呢?

Fra*_*esc 44

我喜欢这样做:

companion object {
    private const val MY_BOOLEAN = "my_boolean"
    private const val MY_INT = "my_int"

    fun newInstance(aBoolean: Boolean, anInt: Int) = MyFragment().apply {
        arguments = Bundle(2).apply {
            putBoolean(MY_BOOLEAN, aBoolean)
            putInt(MY_INT, anInt)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:使用KotlinX扩展,您也可以执行此操作

companion object {
    private const val MY_BOOLEAN = "my_boolean"
    private const val MY_INT = "my_int"

    fun newInstance(aBoolean: Boolean, anInt: Int) = MyFragment().apply {
        arguments = bundleOf(
            MY_BOOLEAN to aBoolean,
            MY_INT to anInt)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 构造函数必须是公共的并且没有参数,因为框架将使用反射来查找构造函数并在重新创建片段时实例化片段(旋转、从后台恢复,...)。 (2认同)

jt-*_*son 10

聚会迟到了,但我相信习惯上应该是这样的:

private const val FOO = "foo"
private const val BAR = "bar"

class MyFragment : Fragment() {
    companion object {
        fun newInstance(foo: Int, bar: String) = MyFragment().withArgs {
            putInt(FOO, foo)
            putString(BAR, bar)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样的扩展:

inline fun <T : Fragment> T.withArgs(argsBuilder: Bundle.() -> Unit): T =
    this.apply {
        arguments = Bundle().apply(argsBuilder)
    }
Run Code Online (Sandbox Code Playgroud)

或者

companion object {
    fun newInstance(foo: Int, bar: String) = MyFragment().apply {
        arguments = bundleOf(
            FOO to foo,
            BAR to bar
        )
    }
 } 
Run Code Online (Sandbox Code Playgroud)

关键是私有常量不应该是伴随对象的一部分。


Mus*_*ven 10

companion object {
  private const val NOTE_ID = "NOTE_ID"
  fun newInstance(noteId: Int?) = AddNoteFragment().apply {
  arguments =
      Bundle().apply { putInt(NOTE_ID, noteId ?: Int.MIN_VALUE) }
  }
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  super.onViewCreated(view, savedInstanceState)
  arguments?.let {
    noteId = it.getInt(NOTE_ID)
  } 
}
Run Code Online (Sandbox Code Playgroud)


Dmi*_*ide 8

inline fun <reified T : Fragment>
    newFragmentInstance(vararg params: Pair<String, Any>) =
    T::class.java.newInstance().apply {
        arguments = bundleOf(*params)
    }`
Run Code Online (Sandbox Code Playgroud)

因此它的用法如下:

val fragment = newFragmentInstance<YourFragment>("key" to value)
Run Code Online (Sandbox Code Playgroud)

信用

bundleOf()可以从安口带走

  • 花哨的,但实际上并不能解决整个“静态newInstance(..)” charade要解决的问题;即以静态工厂方法编码片段的***必需参数。现在,您必须在多个位置编写“键”,并且可能在某个时候忘记它,在某个时候无法修改等等,所以这意味着您可以使用您的助手来实现它,例如“伴侣对象”。 {fun newInstance(name:String)= newFragmentInstance &lt;MyFragment&gt;(“名称”为名称)` (2认同)