Parcelable প্রয়োগ করার জেনারেটর

kotlin-parcelize প্লাগ-ইন একটি Parcelable ইমপ্লিমেন্টেশন জেনারেটর প্রদান করে।

Parcelable-এর জন্য সহায়তা যোগ করতে, আপনার অ্যাপের build.gradle ফাইলে Gradle প্লাগ-ইন যোগ করুন:

গ্ৰুভি

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

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
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-এর আগে, আপনি expect এবং actual-এর সাহায্যে Parcelize অ্যানোটেশন অ্যালিয়াস করে 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 ও এর পরের যেকোনও ভার্সনে, প্লাগ-ইন ট্রিগার করে এমন অ্যালায়াসিং অ্যানোটেশন কাজ করে না। এটি এড়াতে, প্লাগ-ইনে Parcelize নতুন অ্যানোটেশনকে additionalAnnotation প্যারামিটার হিসেবে দিন।

// 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 হতে হয়। এটি ইনহেরিটেন্সের সাথে পার্সেলাইজ ব্যবহার করার একটি সমস্যা সমাধান করে, যেখানে আগে 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 প্লাগ-ইন নিয়ে কোনও সমস্যা হলে, আপনি বাগ সংক্রান্ত অভিযোগ জানাতে পারেন।