পারসেলেবল বাস্তবায়ন জেনারেটর

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

Parcelable জন্য সমর্থন অন্তর্ভুক্ত করতে, আপনার অ্যাপের build.gradle ফাইলে Gradle প্লাগইনটি যোগ করুন:

গ্রুভি

plugins {
    id 'kotlin-parcelize'
}

কোটলিন

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

পার্সেল থেকে ডেটা তৈরি করুন

জাভা কোডে আপনি সরাসরি CREATOR ফিল্ডটি অ্যাক্সেস করতে পারেন।

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

কোটলিনে সরাসরি 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

প্রপার্টির মানটি অ্যান্ড্রয়েড দ্বারা নেটিভভাবে সমর্থিত না হলে এটি রানটাইমে ব্যর্থ হতে পারে।

যখন প্রপার্টিটিকে সিরিয়ালাইজ করার অন্য কোনো উপায় থাকে না, তখন 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 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 এবং এর পরবর্তী সংস্করণগুলিতে, প্লাগইন ট্রিগার করে এমন অ্যানোটেশনের অ্যালিয়াসিং সমর্থিত নয়। এই সমস্যা এড়ানোর জন্য, প্লাগইনের 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 দ্বারা সমর্থিত হতে হবে। কাস্টম পার্সেলার (Custom Parcelers) বেছে নেওয়া হলে, তা ডেটা ক্লাসে নয় , বরং Parcelable ক্লাসে উল্লেখ করতে হবে। যদি ডেটা ক্লাস একই সাথে Serializable ইমপ্লিমেন্ট করে, তাহলে @DataClass অ্যানোটেশনটি অগ্রাধিকার পাবে: android.os.Parcel.writeSerializable ব্যবহৃত হবে না।

এর একটি বাস্তব প্রয়োগ হলো kotlin.Pair সিরিয়ালাইজ করা। আরেকটি দরকারি উদাহরণ হলো মাল্টিপ্ল্যাটফর্ম কোডকে সরল করা: সাধারণ কোড ডেটা লেয়ারকে ডেটা ক্লাস হিসেবে ঘোষণা করতে পারে, যেগুলোকে অ্যান্ড্রয়েড কোড পরবর্তীতে সিরিয়ালাইজেশন লজিক দিয়ে সমৃদ্ধ করতে পারে, ফলে সাধারণ কোডে অ্যান্ড্রয়েড-নির্দিষ্ট অ্যানোটেশন এবং টাইপ অ্যালিয়াসের প্রয়োজনীয়তা দূর হয়।

// 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

প্রাইমারি কনস্ট্রাক্টরে নন-ভ্যাল বা ভ্যার প্যারামিটার

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 প্লাগইনটি নিয়ে কোনো সমস্যা হলে, আপনি একটি বাগ রিপোর্ট করতে পারেন।