Skip to content

Instantly share code, notes, and snippets.

@mahdiPourkazemi
Created July 21, 2025 06:55
Show Gist options
  • Save mahdiPourkazemi/f3aed6c890adc40f0be065c8f383e408 to your computer and use it in GitHub Desktop.
Save mahdiPourkazemi/f3aed6c890adc40f0be065c8f383e408 to your computer and use it in GitHub Desktop.
This Kotlin extension defines a custom NavType<T> mapper for use with Jetpack Navigation when passing Parcelable objects between destinations. It also integrates Kotlinx Serialization (@serializable) for safely encoding and decoding data into string format when navigating via routes. The mapper() function simplifies handling complex objects like…
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import androidx.navigation.NavType
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
/**
* A simple data class representing a person, which can be passed between navigation destinations.
*
* @property name The name of the person.
* @property age The age of the person.
*/
@Serializable // Enables JSON serialization/deserialization using kotlinx.serialization
@Parcelize // Implements Parcelable without boilerplate
data class Person(val name: String, val age: Int) : Parcelable
/**
* Creates a custom [NavType] that handles navigation arguments of type [T], where [T] must be [Parcelable].
* This allows passing complex objects like data classes through Jetpack Navigation arguments.
*
* The value is serialized into a JSON string and deserialized back into an object using kotlinx.serialization.
*
* @return A custom [NavType] that knows how to store and retrieve [T] from a [Bundle] and serialize it.
*/
inline fun <reified T : Parcelable> NavType.Companion.mapper(): NavType<T> {
return object : NavType<T>(isNullableAllowed = false) {
/**
* Inserts the [value] into the [bundle] under the given [key].
*/
override fun put(bundle: Bundle, key: String, value: T) {
bundle.putParcelable(key, value)
}
/**
* Retrieves a value of type [T] from the [bundle] using the given [key].
* Supports backward compatibility for older Android versions.
*/
override fun get(bundle: Bundle, key: String): T? {
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
bundle.getParcelable(key)
} else {
bundle.getParcelable(key, T::class.java)
}
}
/**
* Parses a JSON [value] string and returns the deserialized object of type [T].
*/
override fun parseValue(value: String): T {
return Json.decodeFromString<T>(value)
}
/**
* Serializes the [value] into a JSON string.
*/
override fun serializeAsValue(value: T): String {
return Json.encodeToString(value)
}
/**
* Returns the class name of [T] as the name for the navigation argument type.
*/
override val name = T::class.java.name
}
}
@mahdiPourkazemi
Copy link
Author

mahdiPourkazemi commented Jul 21, 2025

import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import androidx.navigation.NavType
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

/**

  • داده‌ای که بین صفحات جابه‌جا می‌شود.
    • این کلاس هم Parcelable است برای ذخیره در Bundle.
    • و هم Serializable برای تبدیل به JSON هنگام انتقال در route.
      */

@serializable
@parcelize
data class Person(
val name: String,
val age: Int
) : Parcelable

/**

  • تولید یک NavType سفارشی برای استفاده در Jetpack Compose Navigation
  • برای کلاس‌هایی که Parcelable هستند.
  • این تابع به کمک inline و reified به ما اجازه می‌دهد که نوع را
  • در زمان اجرا نیز بشناسیم و بدون نیاز به تعریف دستی NavType برای هر کلاس،
  • فقط با صدا زدن NavType.mapper<MyType>() نوع مورد نظر را بسازیم.
  • @param T نوع داده‌ای که باید قابل پارسل‌سازی باشد.
  • @return یک پیاده‌سازی از NavType<T> که توانایی تبدیل داده به/از Bundle و JSON را دارد.
    */

inline fun NavType.Companion.mapper(): NavType {
return object : NavType(
isNullableAllowed = false
) {
/**
* ذخیره‌ی آبجکت در Bundle با استفاده از putParcelable.
*
* @param bundle بسته‌ای که داده باید در آن ذخیره شود.
* @param key کلیدی که داده با آن در Bundle ذخیره می‌شود.
* @param value شیء مورد نظر برای ذخیره.
*/

    override fun put(bundle: Bundle, key: String, value: T) {
        bundle.putParcelable(key, value)
    }

    /**
     * بازیابی آبجکت از `Bundle` با توجه به نسخه اندروید.
     *
     * @param bundle بسته‌ای که داده از آن بازیابی می‌شود.
     * @param key کلیدی که داده با آن ذخیره شده بود.
     * @return شیء بازیابی شده یا `null` اگر پیدا نشد.
     */
     
    override fun get(bundle: Bundle, key: String): T? {
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            @Suppress("DEPRECATION")
            bundle.getParcelable(key)
        } else {
            bundle.getParcelable(key, T::class.java)
        }
    }

    /**
     * تبدیل یک رشته JSON به آبجکت از نوع `T`.
     *
     * @param value رشته‌ی JSON.
     * @return شیء معادل از نوع `T`.
     */
     
    override fun parseValue(value: String): T {
        return Json.decodeFromString(value)
    }

    /**
     * تبدیل آبجکت به رشته JSON برای انتقال در مسیر (route).
     *
     * @param value آبجکت مورد نظر.
     * @return رشته‌ی JSON معادل.
     */
     
    override fun serializeAsValue(value: T): String {
        return Json.encodeToString(value)
    }

    /**
     * نام نوع NavType برای شناسایی در سیستم Navigation.
     */
     
    override val name = T::class.java.name
}

}

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