Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Painless android fragments with Kotlin

Starting new fragments with Kotlin is easy

Example

val user = User(id = "id", name = "Ruby")
val userFragment: UserFragment = newFragment<User, UserFragment>(user)

How this magic works

1. Define BaseFragment with ARG Parcelable type parameter.

abstract class BaseFragment<ARG : Parcelable> : Fragment() {
    //...
}

1.1. Inside BaseFragment onCreate call getParcelable(FRAGMENT_ARG).

const val FRAGMENT_ARG = "FRAGMENT_ARG"

abstract class BaseFragment<ARG : Parcelable> : Fragment() {
    protected lateinit var arg: ARG

    @CallSuper
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            arg = it.getParcelable(FRAGMENT_ARG)!!
        }
    }
}

2. Define newFragment inline function with 2 type parameters

1. ARG - Parcelable argument type

2. reified T your fragment type

inline fun <ARG : Parcelable, reified T : BaseFragment<ARG>> newFragment(arg: ARG? = null): T {
   //...
}

2.1. Put ARG as fragment argument with bundle.putParcelable(FRAGMENT_ARG, arg)

const val FRAGMENT_ARG = "FRAGMENT_ARG"

inline fun <ARG : Parcelable, reified T : BaseFragment<ARG>> newFragment(arg: ARG? = null): T {
    val fragment = T::class.java.newInstance()
    val bundle = Bundle()
    bundle.putParcelable(FRAGMENT_ARG, arg)
    fragment.arguments = bundle
    return fragment
}

3. Create Parcelable fragment argument (Kotlin Android Extensions)

@Parcelize
data class User(val id: String, val name: String) : Parcelable

3.1. Inherit from BaseFragment and fill the type parameter with your Parcelable argumnet

class UserFragment : BaseFragment<User>() {

}

4. Create new fragment with newFragment function and pass the Parcelable argument

val user = User("id", "Ruby")
val userFragment = newFragment<UserFragment>(user)

3.2 In your fragment you can use arg

class UserFragment : BaseFragment<User>() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val user = arg
        showUser(user)
    }

    private fun showUser(user: User) {

    }
}

6. Enjoy and star :)

@Zhuinden

This comment has been minimized.

Copy link

@Zhuinden Zhuinden commented Jan 9, 2019

If I have no arguments, then this will crash at the !!, no?

@Xstar97

This comment has been minimized.

Copy link

@Xstar97 Xstar97 commented Jan 10, 2019

If I have no arguments, then this will crash at the !!, no?

Yes, thats why use "?" Instead, also add an error/ blank case so it doesn't crash...

@prithivraj

This comment has been minimized.

Copy link

@prithivraj prithivraj commented Jan 10, 2019

Looks cool!
How is this approach better than safeargs?

@amirulzin

This comment has been minimized.

Copy link

@amirulzin amirulzin commented Jan 10, 2019

You can check if the FRAGMENT_ARG exist via Bundle.containsKey hence allowing nullable parameters as needed.

@ozbek

This comment has been minimized.

Copy link

@ozbek ozbek commented Jan 10, 2019

How to correctly get an instance of app context?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment