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
कई तरह के टाइप के साथ काम करता है:
- प्राइमटिव टाइप (और उनके बॉक्स किए गए वर्शन)
- ऑब्जेक्ट और एनम
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
पार्सल से डेटा बनाना
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 का इस्तेमाल करना
किसी प्रॉपर्टी के लिए Parcelize का इस्तेमाल Parcel.writeValue
करने के लिए, उस टाइप के लिए @RawValue
का इस्तेमाल किया जा सकता है.
@Parcelize
class MyClass(val external: @RawValue ExternalClass): Parcelable
अगर प्रॉपर्टी की वैल्यू, Android में पहले से काम नहीं करती, तो हो सकता है कि रनटाइम के दौरान यह काम न करे.
हो सकता है कि प्रॉपर्टी को सीरियलाइज़ करने का कोई दूसरा तरीका न होने पर, पार्सल करने के लिए भी आपको इस एनोटेशन का इस्तेमाल करना पड़े.
सील की गई क्लास और सील किए गए इंटरफ़ेस की मदद से पार्सल करना
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 मल्टीप्लैटफ़ॉर्म के लिए Parcelize सेटअप करना
Kotlin 2.0 से पहले, आप expect
और actual
के साथ पार्सलाइज़ एनोटेशन को एलियाज़ करके पार्सलाइज़ का इस्तेमाल कर सकते थे:
// 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
को सीरियल करना है.
एक और उपयोगी उदाहरण है
multiplatform code:
सामान्य कोड को डेटा क्लास के तौर पर बताना, जिसे 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 प्लग इन से जुड़ी कोई समस्या आती है, तो गड़बड़ी की शिकायत की जा सकती है.