web-dev-qa-db-de.com

Kotlin - idiomatische Methode zum Erstellen eines Fragment NewInstance-Musters

Die bewährte Methode für Android zum Erstellen einer Fragment besteht darin, eine statische Factory-Methode zu verwenden und Argumente in einer Bundle über setArguments() zu übergeben. 

In Java geschieht dies in etwa wie folgt:

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

In Kotlin konvertiert dies zu:

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

Es ist sinnvoll, Interop mit Java zu unterstützen, sodass es immer noch über MyFragment.newInstance(...) aufgerufen werden kann. Aber gibt es in Kotlin einen idiotischeren Weg, dies zu tun, wenn wir uns nicht mit Java-Interop befassen müssen?

11
triad

Ich mache das gerne so:

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

Bearbeiten: Mit KotlinX-Erweiterungen können Sie dies auch tun

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)
    }
}
27
Francesc
inline fun <reified T : Fragment>
    newFragmentInstance(vararg params: Pair<String, Any>) =
    T::class.Java.newInstance().apply {
        arguments = bundleOf(*params)
    }`

So wird es so verwendet:

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

Kredit

bundleOf() kann aus Anko entnommen werden

4
Dmide

Spät zur Party, aber ich glaube idiomatisch sollte es so etwas sein:

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

Mit einer Erweiterung wie dieser:

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

oder

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

Der Schlüssel ist, dass die privaten Konstanten nicht Teil des Begleitobjekts sein sollten.

2
jt-gilkeson

Ein anderer Weg, dies zu tun, ich hier gefunden

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
    }
    ...
  }
  ...
}
1
Xar E Ahmer

Kotlin-Funktion auf Paketebene

Wie steht es mit diesem Kotlin, dass die Funktion auf Paketebene anstelle der statischen Methode verwendet wird

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()
    }
}
0
Irving Lóp