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

时间:2017-11-03 21:02:00

标签: android android-fragments kotlin

Android上用于创建Fragment的最佳做法是使用静态工厂方法,并通过BundlesetArguments()中传递参数。

在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;
    }
}

在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
        }
    }
}

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

7 个答案:

答案 0 :(得分:36)

我喜欢这样做:

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)
        }
    }
}

编辑:使用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)
    }
}

答案 1 :(得分:5)

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

所以就像这样使用:

val fragment = newFragmentInstance<YourFragment>("key" to value)

Credit

bundleOf()可以从Anko

获取

答案 2 :(得分:1)

另一种方式我found here

class MyFragment: Fragment(){
  companion object{
    private val ARG_CAUGHT = "myFragment_caught"

    fun newInstance(caught: Pokemon):MyFragment{
      val args: Bundle = Bundle()
      args.putSerializable(ARG_CAUGHT, caught)
      val fragment = MyFragment()
      fragment.arguments = args
      return fragment
    }
    ...
  }
  ...
}

答案 3 :(得分:1)

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

Snap (Workshop Bookings) {
    "-Lb4XzGtLtnBAgoPB6Ay" =     {
        "Booking Date" = 20190329;
        "Booking End" = "14:00";
        "Booking Id" = 201903291300;
        "Booking Start" = "13:00";
        "Shop Logo Url" = "https://firebasestorage.googleapis.com/v0/b/fix-it-b4b00.appspot.com/o/Spezial%20Cycle%2FSpezial%20Cycle%20logo.png?alt=media&token=016cc976-ae8d-4c71-a77f-a899d661be20";
        "Shop Name" = "Spezial Cycle";
        "User Name" = "";
        "Works List" = "Revisione Generale, ";
    };
} 

具有这样的扩展名:

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)
        }
    }
}

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

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

答案 4 :(得分:1)

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)
  } 
}

答案 5 :(得分:1)

我认为更优雅的方式

open class Instance<T : Fragment> {

    @Suppress("UNCHECKED_CAST")
    fun newInstance(vararg args: Pair<String, Any?>): T {
        val cls = Class.forName(javaClass.name.substringBefore("$"))
        return (cls.newInstance() as T).apply {
            arguments = bundleOf(*args)
        }
    }
}

class MyFragment : Fragment() {

    companion object : Instance<MyFragment>()
}

记住添加proguard规则来保存构造函数

-keepclassmembers class * extends androidx.fragment.app.Fragment {
   <init>(...);
}

或者没有反射和proguard

open class Instance<T : Fragment>(private val cls: Class<T>) {

    fun newInstance(vararg args: Pair<String, Any?>): T {
        return cls.newInstance().apply {
            arguments = bundleOf(*args)
        }
    }
}

class MyFragment : Fragment() {

    companion object : Instance<MyFragment>(MyFragment::class.java)
}

使用示例

val myFragment = MyFragment.newInstance("foo" to "bar)

答案 6 :(得分:0)

Kotlin包级功能

关于Kotlin所说的使用包级功能而不是“静态”方法的事

MyFragment.kt

class MyFragment : Fragment() {

    .....

}

fun MyFragmentNewInstance(): MyFragment {
    return MyFragment()
}

MyActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if (supportFragmentManager.findFragmentById(R.id.fragmentContainer) == null) {
        supportFragmentManager.beginTransaction()
            .add(R.id.fragmentContainer, MyFragmentNewInstance())
            .commit()
    }
}