पार्स किया जा सकने वाला लागू करने वाला जनरेटर

kotlin-parcelize प्लगिन, Parcelable लागू करने वाला जनरेटर उपलब्ध कराता है.

Parcelable के लिए सहायता शामिल करने के लिए, अपने ऐप्लिकेशन की build.gradle फ़ाइल में Gradle प्लगिन जोड़ें:

Groovy

plugins {
    id 'kotlin-parcelize'
}

Kotlin

plugins {
    id("kotlin-parcelize")
}

किसी क्लास को @Parcelize से एनोटेट करने पर, Parcelable लागू करने का तरीका अपने-आप जनरेट हो जाता है. इसे यहां दिए गए उदाहरण में दिखाया गया है:

// import kotlinx.parcelize.Parcelize

@Parcelize
class User(val firstName: String, val lastName: String, val age: Int) : Parcelable

@Parcelize के लिए, सभी क्रम से लगाई गई प्रॉपर्टी को प्राइमरी कंस्ट्रक्टर में एलान करना ज़रूरी है. यह प्लगिन, क्लास बॉडी में बैकअप फ़ील्ड के साथ डिक्लेयर की गई हर प्रॉपर्टी के लिए चेतावनी जारी करता है. इसके अलावा, अगर प्राइमरी कंस्ट्रक्टर के कुछ पैरामीटर प्रॉपर्टी नहीं हैं, तो @Parcelize लागू नहीं किया जा सकता.

अगर आपकी क्लास के लिए, ज़्यादा बेहतर सीरियलाइज़ेशन लॉजिक की ज़रूरत है, तो उसे कंपैनियन क्लास में लिखें:

@Parcelize
data class User(val firstName: String, val lastName: String, val age: Int) : Parcelable {
    private companion object : Parceler<User> {
        override fun User.write(parcel: Parcel, flags: Int) {
            // Custom write implementation
        }

        override fun create(parcel: Parcel): User {
            // Custom read implementation
        }
    }
}

इस्तेमाल किए जा सकने वाले टाइप

@Parcelize कई तरह के टाइप के साथ काम करता है:

  • प्रिमिटिव टाइप (और उनके बॉक्स वाले वर्शन)
  • ऑब्जेक्ट और enum
  • String, CharSequence
  • Duration
  • Exception
  • Size, SizeF, Bundle, IBinder, IInterface, FileDescriptor
  • SparseArray, SparseIntArray, SparseLongArray, SparseBooleanArray
  • सभी Serializable (इसमें Date शामिल है) और Parcelable लागू करने की प्रोसेस
  • सभी तरह के कलेक्शन: List (ArrayList पर मैप किया गया), Set (LinkedHashSet पर मैप किया गया), Map (LinkedHashMap पर मैप किया गया)
    • इसके अलावा, कई कॉन्क्रीट इंप्लीमेंटेशन भी हैं: ArrayList, LinkedList, SortedSet, NavigableSet, HashSet, LinkedHashSet, TreeSet, SortedMap, NavigableMap, HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap
  • सभी तरह के डेटा टाइप की ऐरे
  • सभी काम करने वाले टाइप के नल हो सकने वाले वर्शन

पसंद के मुताबिक Parceler

अगर आपका टाइप सीधे तौर पर मौजूद नहीं है, तो इसके लिए Parceler मैपिंग ऑब्जेक्ट लिखा जा सकता है.

class ExternalClass(val value: Int)

object ExternalClassParceler : Parceler<ExternalClass> {
    override fun create(parcel: Parcel) = ExternalClass(parcel.readInt())

    override fun ExternalClass.write(parcel: Parcel, flags: Int) {
        parcel.writeInt(value)
    }
}

@TypeParceler या @WriteWith एनोटेशन का इस्तेमाल करके, पार्सल करने वाली बाहरी कंपनियों की जानकारी दी जा सकती है:

// Class-local parceler
@Parcelize
@TypeParceler<ExternalClass, ExternalClassParceler>()
class MyClass(val external: ExternalClass) : Parcelable

// Property-local parceler
@Parcelize
class MyClass(@TypeParceler<ExternalClass, ExternalClassParceler>() val external: ExternalClass) : Parcelable

// Type-local parceler
@Parcelize
class MyClass(val external: @WriteWith<ExternalClassParceler>() ExternalClass) : Parcelable

Parcel से डेटा बनाना

Java कोड में, CREATOR फ़ील्ड को सीधे तौर पर ऐक्सेस किया जा सकता है.

class UserCreator {
    static User fromParcel(Parcel parcel) {
        return User.CREATOR.createFromParcel(parcel);
    }
}

Kotlin में, CREATOR फ़ील्ड का सीधे तौर पर इस्तेमाल नहीं किया जा सकता. इसके बजाय, kotlinx.parcelize.parcelableCreator का इस्तेमाल करें.

// import kotlinx.parcelize.parcelableCreator

fun userFromParcel(parcel: Parcel): User {
    return parcelableCreator<User>().createFromParcel(parcel)
}

सीरियलाइज़ेशन से प्रॉपर्टी स्किप करना

अगर आपको किसी प्रॉपर्टी को पार्सल करने से रोकना है, तो @IgnoredOnParcel एनोटेशन का इस्तेमाल करें. इसका इस्तेमाल किसी क्लास के बॉडी में मौजूद प्रॉपर्टी पर भी किया जा सकता है, ताकि प्रॉपर्टी के क्रम से न लगाए जाने के बारे में चेतावनियों को हटाया जा सके. @IgnoredOnParcel के साथ एनोटेट की गई कंस्ट्रक्टर प्रॉपर्टी की डिफ़ॉल्ट वैल्यू होनी चाहिए.

@Parcelize
class MyClass(
    val include: String,
    // Don't serialize this property
    @IgnoredOnParcel val ignore: String = "default"
) : Parcelable {
    // Silence a warning
    @IgnoredOnParcel
    val computed: String = include + ignore
}

किसी प्रॉपर्टी को क्रम से लगाने के लिए, android.os.Parcel.writeValue का इस्तेमाल करना

किसी टाइप को @RawValue के साथ एनोटेट किया जा सकता है, ताकि Parcelize उस प्रॉपर्टी के लिए Parcel.writeValue का इस्तेमाल करे.

@Parcelize
class MyClass(val external: @RawValue ExternalClass) : Parcelable

अगर प्रॉपर्टी की वैल्यू, Android के साथ काम नहीं करती है, तो रनटाइम के दौरान यह फ़ेल हो सकती है.

अगर प्रॉपर्टी को क्रम से लगाने का कोई और तरीका नहीं है, तो Parcelize को इस एनोटेशन का इस्तेमाल करने की ज़रूरत पड़ सकती है.

सील्ड क्लास और सील्ड इंटरफ़ेस के साथ पार्सल करना

Parcelize के लिए, पार्सल की जाने वाली क्लास का ऐब्स्ट्रैक्ट न होना ज़रूरी है. यह सीमा, सील की गई क्लास के लिए लागू नहीं होती. अगर किसी सील की गई क्लास पर @Parcelize एनोटेशन का इस्तेमाल किया जाता है, तो उससे मिलने वाली क्लास के लिए इसे दोहराने की ज़रूरत नहीं होती.

@Parcelize
sealed class SealedClass : Parcelable {
    class A(val a: String) : SealedClass()
    class B(val b: Int) : SealedClass()
}

@Parcelize
class MyClass(val a: SealedClass.A, val b: SealedClass.B, val c: SealedClass) : Parcelable

Kotlin Multiplatform के लिए Parcelize को सेटअप करना

Kotlin 2.0 से पहले, Parcelize एनोटेशन को expect और actual के साथ एलियास करके, Parcelize का इस्तेमाल किया जा सकता था:

// Common code
package example

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
expect annotation class MyParcelize()

expect interface MyParcelable

@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.SOURCE)
expect annotation class MyIgnoredOnParcel()

@MyParcelize
class MyClass(
    val x: String,
    @MyIgnoredOnParcel val y: String = ""
): MyParcelable

// Platform code
package example

actual typealias MyParcelize = kotlinx.parcelize.Parcelize
actual typealias MyParcelable = android.os.Parcelable
actual typealias MyIgnoredOnParcel = kotlinx.parcelize.IgnoredOnParcel

Kotlin 2.0 और इसके बाद के वर्शन में, प्लगिन को ट्रिगर करने वाले एनोटेशन के लिए एलियासिंग की सुविधा काम नहीं करती. इससे बचने के लिए, प्लगिन को additionalAnnotation पैरामीटर के तौर पर नया Parcelize एनोटेशन दें.

// Gradle build configuration
kotlin {
    androidTarget {
        compilerOptions {
            // ...
            freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=example.MyParcelize")
        }
    }
}

// Common code
// package example

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
// No `expect` keyword here
annotation class MyParcelize()

expect interface MyParcelable

@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.SOURCE)
expect annotation class MyIgnoredOnParcel()

@MyParcelize
class MyClass(
    val x: String,
    @MyIgnoredOnParcel val y: String = ""
) : MyParcelable

// Platform code
// package example

// No typealias for MyParcelize here
actual typealias MyParcelable = android.os.Parcelable
actual typealias MyIgnoredOnParcel = kotlinx.parcelize.IgnoredOnParcel

Parcel इंटरफ़ेस सिर्फ़ Android पर उपलब्ध है. इसलिए, Parcelize अन्य प्लैटफ़ॉर्म पर कोई कोड जनरेट नहीं करेगा. इसलिए, वहां actual के सभी लागू किए गए कोड खाली हो सकते हैं. साथ ही, सामान्य कोड में ऐसे किसी भी एनोटेशन का इस्तेमाल नहीं किया जा सकता जिसके लिए Parcel क्लास का रेफ़रंस देना ज़रूरी हो. उदाहरण के लिए, @WriteWith.

प्रयोग के तौर पर शुरू की गई सुविधाएं

डेटा क्लास सीरियलाइज़र

यह सुविधा Kotlin 2.1.0 से उपलब्ध है.

DataClass एनोटेशन की मदद से, डेटा क्लास को इस तरह से क्रम से लगाया जा सकता है जैसे कि उन्हें Parcelize से एनोटेट किया गया हो. इस एनोटेशन के लिए, kotlinx.parcelize.Experimental में ऑप्ट-इन करना ज़रूरी है.

// @file:OptIn(kotlinx.parcelize.Experimental::class)

data class C(val a: Int, val b: String)

@Parcelize
class P(val c: @DataClass C) : Parcelable

प्राइमरी कंस्ट्रक्टर और उसकी सभी प्रॉपर्टी, Parcelable क्लास से ऐक्सेस की जा सकती हों. इसके अलावा, डेटा क्लास की सभी प्राइमरी कंस्ट्रक्टर प्रॉपर्टी, Parcelize के साथ काम करनी चाहिए. अगर कस्टम पार्सलर चुने जाते हैं, तो उन्हें Parcelable क्लास में तय किया जाना चाहिए, डेटा क्लास में नहीं. अगर डेटा क्लास में Serializable को भी लागू किया जाता है, तो @DataClass एनोटेशन को प्राथमिकता मिलती है: android.os.Parcel.writeSerializable का इस्तेमाल नहीं किया जाएगा.

इसका एक व्यावहारिक उदाहरण, kotlin.Pair को क्रम से लगाना है. एक और उपयोगी उदाहरण, मल्टीप्लैटफ़ॉर्म कोड को आसान बनाना है: कॉमन कोड, डेटा लेयर को डेटा क्लास के तौर पर एलान कर सकता है. इसके बाद, Android कोड इसे क्रम से लगाने के लॉजिक के साथ बढ़ा सकता है. इससे कॉमन कोड में Android के लिए खास एनोटेशन और टाइप एलियास की ज़रूरत नहीं होगी.

// Common code:
data class MyData(val x: String, val y: MoreData)
data class MoreData(val a: String, val b: Int)

// Platform code:
@OptIn(kotlinx.parcelize.Experimental::class)
@Parcelize
class DataWrapper(val wrapped: @DataClass MyData) : Parcelable

मुख्य कंस्ट्रक्टर में val या var के अलावा अन्य पैरामीटर

यह सुविधा Kotlin 2.1.0 से उपलब्ध है.

इस सुविधा को चालू करने के लिए, parcelize प्लगिन के आर्ग्युमेंट में experimentalCodeGeneration=true जोड़ें.

kotlin {
    compilerOptions {
        // ...
        freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
    }
}

इस सुविधा की मदद से, मुख्य कंस्ट्रक्टर के ऐसे आर्ग्युमेंट पर लगी पाबंदी हट जाती है जिन्हें val या var होना चाहिए. इससे इनहेरिटेंस के साथ parcelize का इस्तेमाल करने से जुड़ी एक समस्या हल हो जाती है. पहले इसके लिए, open प्रॉपर्टी का इस्तेमाल करना पड़ता था.

// base parcelize
@Parcelize
open class Base(open val s: String) : Parcelable

@Parcelize
class Derived(
    val x: Int,
    // all arguments have to be `val` or `var` so we need to override
    // to not introduce new property name
    override val s: String
) : Base(s)

// experimental code generation enabled
@Parcelize
open class Base(val s: String): Parcelable

@Parcelize
class Derived(val x: Int, s: String): Base(s)

इस तरह के पैरामीटर का इस्तेमाल सिर्फ़ बेस क्लास कंस्ट्रक्टर के आर्ग्युमेंट में किया जा सकता है. क्लास के मुख्य हिस्से में उनका रेफ़रंस देने की अनुमति नहीं है.

@Parcelize
class Derived(s: String): Base(s) { // allowed
    @IgnoredOnParcel
    val x: String = s // ERROR: not allowed.
    init {
        println(s) // ERROR: not allowed
    }
}

सुझाव/राय दें या शिकायत करें

अगर आपको kotlin-parcelize Gradle प्लगिन से जुड़ी कोई समस्या आती है, तो गड़बड़ी की शिकायत करें.