DataStore   Android Jetpack-এর অংশ।

Kotlin Multiplatform ব্যবহার করে দেখুন
Kotlin Multiplatform অন্যান্য প্ল্যাটফর্মের সাথে ডেটা লেয়ার শেয়ার করার অনুমতি দেয়। KMP-তে কীভাবে DataStore সেট-আপ ও ব্যবহার করতে হয় তা জানুন

Jetpack DataStore হল ডেটা স্টোরেজ সংক্রান্ত সমাধান যা আপনাকে প্রোটোকল বাফার সহ কী-ভ্যালু পেয়ার বা টাইপ করা অবজেক্ট স্টোর করতে দেয়। ডেটা অ্যাসিঙ্ক্রোনাস, সামঞ্জস্যপূর্ণ এবং ট্রানজ্যাকশনাল উপায়ে স্টোর করার জন্য DataStore, Kotlin করুটিন ও Flow ব্যবহার করে।

আপনি ডেটা স্টোর করার জন্য SharedPreferences ব্যবহার করলে, DataStore-এ মাইগ্রেট করার কথা বিবেচনা করুন।

DataStore API

DataStore ইন্টারফেস নিম্নলিখিত API প্রদান করে:

  1. DataStore থেকে ডেটা রিড করার জন্য ব্যবহার করা যেতে পারে এমন একটি ফ্লো

    val data: Flow<T>
    
  2. DataStore-এ ডেটা আপডেট করার ফাংশন

    suspend updateData(transform: suspend (t) -> T)
    

DataStore কনফিগারেশন

আপনি যদি কী ব্যবহার করে ডেটা স্টোর ও অ্যাক্সেস করতে চান, তাহলে Preferences DataStore ইমপ্লিমেন্টেশন ব্যবহার করুন, যার জন্য আগে থেকে নির্ধারিত স্কিমার প্রয়োজন হয় না এবং এটি টাইপ সেফটি প্রদান করে না। এতে SharedPreferences-এর মতো API আছে, কিন্তু শেয়ার করা পছন্দ সংক্রান্ত অসুবিধাগুলি নেই।

DataStore আপনাকে কাস্টম ক্লাস সেভ করতে দেয়। এটি করতে, আপনাকে ডেটার জন্য একটি স্কিমা নির্ধারণ করতে হবে এবং এটিকে একটি পারসিস্টেবল ফর্ম্যাটে কনভার্ট করার জন্য একটি Serializer প্রদান করতে হবে। আপনি Protocol Buffers, JSON বা অন্য কোনও সিরিয়ালাইজেশন স্ট্র্যাটেজি ব্যবহার করতে পারেন।

সেট-আপ করুন

আপনার অ্যাপে Jetpack DataStore ব্যবহার করতে, আপনি কোন ইমপ্লিমেন্টেশন ব্যবহার করতে চান তার উপর নির্ভর করে, আপনার Gradle ফাইলে নিম্নলিখিতগুলি যোগ করুন:

পছন্দ ডেটাস্টোর

আপনার গ্রেডল ফাইলের ডিপেন্ডেন্সি অংশে নিম্নলিখিত লাইনগুলো যোগ করুন:

গ্রুভি

    dependencies {
        // Preferences DataStore (SharedPreferences like APIs)
        implementation "androidx.datastore:datastore-preferences:1.2.1"

        // Alternatively - without an Android dependency.
        implementation "androidx.datastore:datastore-preferences-core:1.2.1"
    }
    

কোটলিন

    dependencies {
        // Preferences DataStore (SharedPreferences like APIs)
        implementation("androidx.datastore:datastore-preferences:1.2.1")

        // Alternatively - without an Android dependency.
        implementation("androidx.datastore:datastore-preferences-core:1.2.1")
    }
    

ঐচ্ছিক RxJava সমর্থন যোগ করতে, নিম্নলিখিত নির্ভরতাগুলি যুক্ত করুন:

গ্রুভি

    dependencies {
        // optional - RxJava2 support
        implementation "androidx.datastore:datastore-preferences-rxjava2:1.2.1"

        // optional - RxJava3 support
        implementation "androidx.datastore:datastore-preferences-rxjava3:1.2.1"
    }
    

কোটলিন

    dependencies {
        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-preferences-rxjava2:1.2.1")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-preferences-rxjava3:1.2.1")
    }
    

ডেটাস্টোর

আপনার গ্রেডল ফাইলের ডিপেন্ডেন্সি অংশে নিম্নলিখিত লাইনগুলো যোগ করুন:

গ্রুভি

    dependencies {
        // Typed DataStore for custom data objects (for example, using Proto or JSON).
        implementation "androidx.datastore:datastore:1.2.1"

        // Alternatively - without an Android dependency.
        implementation "androidx.datastore:datastore-core:1.2.1"
    }
    

কোটলিন

    dependencies {
        // Typed DataStore for custom data objects (for example, using Proto or JSON).
        implementation("androidx.datastore:datastore:1.2.1")

        // Alternatively - without an Android dependency.
        implementation("androidx.datastore:datastore-core:1.2.1")
    }
    

RxJava সমর্থনের জন্য নিম্নলিখিত ঐচ্ছিক নির্ভরতাগুলি যোগ করুন:

গ্রুভি

    dependencies {
        // optional - RxJava2 support
        implementation "androidx.datastore:datastore-rxjava2:1.2.1"

        // optional - RxJava3 support
        implementation "androidx.datastore:datastore-rxjava3:1.2.1"
    }
    

কোটলিন

    dependencies {
        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-rxjava2:1.2.1")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-rxjava3:1.2.1")
    }
    

কন্টেন্ট সিরিয়ালাইজ করতে, প্রোটোকল বাফার্স অথবা JSON সিরিয়ালাইজেশন-এর জন্য ডিপেন্ডেন্সি যোগ করুন।

JSON সিরিয়ালাইজেশন

JSON সিরিয়ালাইজেশন ব্যবহার করতে, আপনার Gradle ফাইলে নিম্নলিখিতটি যোগ করুন:

গ্রুভি

    plugins {
        id("org.jetbrains.kotlin.plugin.serialization") version "2.2.20"
    }

    dependencies {
        implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0"
    }
    

কোটলিন

    plugins {
        id("org.jetbrains.kotlin.plugin.serialization") version "2.2.20"
    }

    dependencies {
        implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
    }
    

প্রোটোবাফ সিরিয়ালাইজেশন

প্রোটোবাফ সিরিয়ালাইজেশন ব্যবহার করতে, আপনার গ্রেডল ফাইলে নিম্নলিখিতটি যোগ করুন:

গ্রুভি

    plugins {
        id("com.google.protobuf") version "0.9.5"
    }
    dependencies {
        implementation "com.google.protobuf:protobuf-kotlin-lite:4.32.1"

    }

    protobuf {
        protoc {
            artifact = "com.google.protobuf:protoc:4.32.1"
        }
        generateProtoTasks {
            all().forEach { task ->
                task.builtins {
                    create("java") {
                        option("lite")
                    }
                    create("kotlin")
                }
            }
        }
    }
    

কোটলিন

    plugins {
        id("com.google.protobuf") version "0.9.5"
    }
    dependencies {
        implementation("com.google.protobuf:protobuf-kotlin-lite:4.32.1")
    }

    protobuf {
        protoc {
            artifact = "com.google.protobuf:protoc:4.32.1"
        }
        generateProtoTasks {
            all().forEach { task ->
                task.builtins {
                    create("java") {
                        option("lite")
                    }
                    create("kotlin")
                }
            }
        }
    }
    

DataStore সঠিকভাবে ব্যবহার করা

DataStore সঠিকভাবে ব্যবহার করতে, সবসময় নিম্নলিখিত নিয়মগুলি মনে রাখবেন:

  1. একই প্রসেসে কোনও ফাইলের জন্য DataStore-এর একাধিক ইনস্ট্যান্স তৈরি করবেন না। এটি করলে, সব DataStore ফাংশনালিটি ভেঙে যেতে পারে। একই প্রসেসে কোনও ফাইলের জন্য একাধিক DataStore অ্যাক্টিভ থাকলে, ডেটা রিড বা আপডেট করার সময় DataStore IllegalStateException থ্রো করবে।

  2. DataStore<T>-এর জেনেরিক ধরন অবশ্যই অপরিবর্তনীয় হতে হবে। DataStore-এ ব্যবহৃত কোনও টাইপ পরিবর্তন করলে, DataStore-এর প্রদান করা কনসিস্টেন্সি বাতিল হয়ে যায় এবং সম্ভাব্য গুরুতর, সহজে ধরা না পড়া বাগ তৈরি হয়। আমরা সাজেস্ট করি যে আপনি প্রোটোকল বাফার ব্যবহার করুন, যা অপরিবর্তনীয়তা, স্পষ্ট API এবং কার্যকর সিরিয়ালাইজেশন নিশ্চিত করতে সাহায্য করে।

  3. একই ফাইলের জন্য SingleProcessDataStore ও MultiProcessDataStore ব্যবহারের পদ্ধতি মিশিয়ে দেবেন না। আপনি যদি DataStore-কে একাধিক প্রসেস থেকে অ্যাক্সেস করতে চান, তাহলে আপনাকে অবশ্যই MultiProcessDataStore ব্যবহার করতে হবে।

ডেটার সংজ্ঞা

Preferences DataStore

ডিস্কে ডেটা সেভ করার জন্য ব্যবহার করা হবে এমন একটি কী নির্ধারণ করুন।

val EXAMPLE_COUNTER = intPreferencesKey("example_counter")

JSON DataStore

JSON ডেটা স্টোরের জন্য, আপনি যে ডেটা সেভ করতে চান সেটিতে @Serialization অ্যানোটেশন যোগ করুন।

@Serializable data class Settings(val exampleCounter: Int)

Serializer<T> প্রয়োগ করে এমন একটি ক্লাসকে সংজ্ঞায়িত করুন, যেখানে T হল আপনি আগে যে ক্লাসে অ্যানোটেশন যোগ করেছেন তার ধরন। কোনও ফাইল এখনও তৈরি না হয়ে থাকলে, ব্যবহার করার জন্য সিরিয়ালাইজারের একটি ডিফল্ট ভ্যালু অন্তর্ভুক্ত করতে ভুলবেন না।

object SettingsSerializer : Serializer<Settings> {

    override val defaultValue: Settings = Settings(exampleCounter = 0)

    override suspend fun readFrom(input: InputStream): Settings =
        try {
            Json.decodeFromString(Settings.serializer(), input.readBytes().decodeToString())
        } catch (serialization: SerializationException) {
            throw CorruptionException("Unable to read Settings", serialization)
        }

    override suspend fun writeTo(t: Settings, output: OutputStream) {
        output.write(Json.encodeToString(Settings.serializer(), t).encodeToByteArray())
    }
}

Proto DataStore

Proto DataStore ইমপ্লিমেন্টেশন, DataStore ও প্রোটোকল বাফার ব্যবহার করে টাইপ করা অবজেক্ট ডিস্কে সেভ করে।

Proto DataStore-এর জন্য app/src/main/proto/ ডিরেক্টরিতে একটি proto ফাইলে আগে থেকে সংজ্ঞায়িত স্কিমা থাকতে হবে। এই স্কিমা, আপনার Proto DataStore-এ সেভ করা অবজেক্টের ধরনকে সংজ্ঞায়িত করে। প্রোটো স্কিমা নির্ধারণ করা সম্পর্কে আরও জানতে, protobuf ভাষা নির্দেশিকা দেখুন।

src/main/proto ফোল্ডারের মধ্যে settings.proto নামের ফাইল যোগ করুন:

syntax = "proto3";

option java_package = "com.example.datastoresampleapp";
option java_multiple_files = true;

message Settings {
  int32 counter = 1;
  bool foo = 2;
}

Serializer<T> প্রয়োগ করে এমন একটি ক্লাসকে সংজ্ঞায়িত করুন, যেখানে T হল প্রোটো ফাইলে সংজ্ঞায়িত টাইপ। এই সিরিয়ালাইজার ক্লাসটি কীভাবে DataStore আপনার ডেটা টাইপ পড়ে এবং লেখে তা নির্ধারণ করে। এখনও কোনও ফাইল তৈরি না হয়ে থাকলে, ব্যবহার করার জন্য সিরিয়ালাইজারের একটি ডিফল্ট ভ্যালু অন্তর্ভুক্ত করতে ভুলবেন না।

object SettingsSerializer : Serializer<Settings> {
    override val defaultValue: Settings = Settings.getDefaultInstance()

    override suspend fun readFrom(input: InputStream): Settings {
        try {
            return Settings.parseFrom(input)
        } catch (exception: InvalidProtocolBufferException) {
            throw CorruptionException("Cannot read proto.", exception)
        }
    }

    override suspend fun writeTo(t: Settings, output: OutputStream) {
        return t.writeTo(output)
    }
}

DataStore তৈরি করা

ডেটা সেভ করার জন্য ব্যবহৃত ফাইলের নাম আপনাকে উল্লেখ করতে হবে।

Preferences DataStore

Preferences DataStore ইমপ্লিমেন্টেশন, ডিস্কে কী-ভ্যালু পেয়ার সেভ করে রাখার জন্য DataStore এবং Preferences ক্লাস ব্যবহার করে। DataStore<Preferences>-এর ইনস্ট্যান্স তৈরি করতে, preferencesDataStore-এর তৈরি করা প্রপার্টি ডেলিগেট ব্যবহার করুন। আপনার Kotlin ফাইলের টপ লেভেলে এটি একবার কল করুন। আপনার অ্যাপ্লিকেশনের বাকি অংশ জুড়ে এই প্রপার্টির মাধ্যমে DataStore অ্যাক্সেস করুন। এর ফলে আপনার DataStore-কে সিঙ্গলটন হিসেবে রাখা সহজ হয়। বাধ্যতামূলক name প্যারামিটার হল Preferences DataStore-এর নাম।

// At the top level of your kotlin file:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")

JSON DataStore

dataStore-এর তৈরি করা প্রপার্টি ডেলিগেট ব্যবহার করে DataStore<T>-এর একটি ইনস্ট্যান্স তৈরি করুন, যেখানে T হল সিরিয়ালাইজ করা যায় এমন ডেটা ক্লাস। আপনার Kotlin ফাইলের টপ-লেভেলে এটি একবার কল করুন এবং আপনার অ্যাপের বাকি অংশ জুড়ে এই প্রপার্টির মাধ্যমে এটি অ্যাক্সেস করুন। fileName প্যারামিটারটি DataStore-কে বলে যে ডেটা স্টোর করার জন্য কোন ফাইল ব্যবহার করতে হবে এবং serializer প্যারামিটারটি DataStore-কে আগে থেকে সংজ্ঞায়িত সিরিয়ালাইজার ক্লাসের নাম বলে।

val Context.dataStore: DataStore<Settings> by
    dataStore(
        fileName = "settings.json",
        serializer = SettingsSerializer,
        scope = CoroutineScope(Dispatchers.IO + SupervisorJob()),
    )

Proto DataStore

dataStore-এর তৈরি করা প্রপার্টি ডেলিগেট ব্যবহার করে DataStore<T>-এর একটি ইনস্ট্যান্স তৈরি করুন, যেখানে T হল প্রোটো ফাইলে সংজ্ঞায়িত ধরন। আপনার Kotlin ফাইলের টপ লেভেলে এটি একবার কল করুন এবং আপনার অ্যাপের বাকি অংশ জুড়ে এই প্রপার্টির মাধ্যমে এটি অ্যাক্সেস করুন। fileName প্যারামিটারটি DataStore-কে কোন ফাইল ব্যবহার করে ডেটা স্টোর করতে হবে তা বলে এবং serializer প্যারামিটারটি DataStore-কে আগে সংজ্ঞায়িত করা সিরিয়ালাইজার ক্লাসের নাম বলে।

val Context.dataStore: DataStore<Settings> by
    dataStore(fileName = "settings.pb", serializer = SettingsSerializer)

DataStore থেকে পড়া

ডেটা সেভ করার জন্য ব্যবহৃত ফাইলের নাম আপনাকে উল্লেখ করতে হবে।

Preferences DataStore

Preferences DataStore আগে থেকে নির্ধারিত স্কিমা ব্যবহার করে না বলে, আপনাকে অবশ্যই DataStore<Preferences> ইনস্ট্যান্সে সেভ করতে হবে এমন প্রতিটি ভ্যালুর জন্য কী নির্ধারণ করতে সংশ্লিষ্ট কী টাইপ ফাংশন ব্যবহার করতে হবে। যেমন, int ভ্যালুর জন্য কী নির্ধারণ করতে, intPreferencesKey ব্যবহার করুন। তারপরে, কোনও ফ্লো ব্যবহার করে উপযুক্ত স্টোর করা ভ্যালু প্রকাশ করতে DataStore.data প্রপার্টি ব্যবহার করুন।

fun counterFlow(): Flow<Int> =
    context.dataStore.data.map { preferences -> preferences[EXAMPLE_COUNTER] ?: 0 }

JSON DataStore

আপনার সেভ করা অবজেক্ট থেকে উপযুক্ত প্রপার্টির Flow এক্সপোজ করতে DataStore.data ব্যবহার করুন।

fun counterFlow(): Flow<Int> =
    context.dataStore.data.map { settings -> settings.exampleCounter }

Proto DataStore

আপনার সেভ করা অবজেক্ট থেকে উপযুক্ত প্রপার্টির Flow এক্সপোজ করতে DataStore.data ব্যবহার করুন।

fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings -> settings.counter }

Composable-এ ViewModel-এর তৈরি করা Flow ব্যবহার করতে collectAsStateWithLifecycle ব্যবহার করুন। এটি নিরাপদে DataStore Flow-কে Compose State-এ কনভার্ট করে যা রিকম্পোজিশন ট্রিগার করে।

@Composable
fun SomeScreen(counterFlow: Flow<Int>) {
  val counter by counterFlow.collectAsStateWithLifecycle(initialValue = 0)
  Text(text = "Example counter: ${counter}")
}

collectAsStateWithLifecycle সম্পর্কে আরও জানতে, State ও Jetpack Compose দেখুন।

DataStore-এ লেখা

DataStore একটি updateData ফাংশন প্রদান করে যা স্টোর করা অবজেক্টকে ট্রানজ্যাকশনালি আপডেট করে। updateData আপনাকে ডেটার বর্তমান অবস্থা দেখায়, এটি আপনার ডেটা টাইপের একটি ইনস্ট্যান্স এবং অ্যাটমিক রিড-রাইট-মডিফাই অপারেশনে ডেটা ট্রানজ্যাকশনালি আপডেট করে। updateData ব্লকের মধ্যে থাকা সব কোডকে একটি ট্রানজ্যাকশন হিসেবে বিবেচনা করা হয়।

Preferences DataStore

suspend fun incrementCounter() {
    context.dataStore.updateData {
        it.toMutablePreferences().also { preferences ->
            preferences[EXAMPLE_COUNTER] = (preferences[EXAMPLE_COUNTER] ?: 0) + 1
        }
    }
}

JSON DataStore

suspend fun incrementCounter() {
    context.dataStore.updateData { settings ->
        settings.copy(exampleCounter = settings.exampleCounter + 1)
    }
}

Proto DataStore

suspend fun incrementCounter() {
    context.dataStore.updateData { settings ->
        settings.toBuilder().setCounter(settings.counter + 1).build()
    }
}

Compose অ্যাপে DataStore ব্যবহার করা

Compose অ্যাপে DataStore ব্যবহার করতে, Android অ্যাপ আর্কিটেকচার সংক্রান্ত নির্দেশিকা অনুসরণ করে আপনার ডেটা লেয়ারে (যেমন, রিপোজিটরি) DataStore অপারেশন রাখা এবং ViewModel-এর মাধ্যমে আপনার UI-তে ডেটা এক্সপোজ করা।

আপনার কম্পোজ করার উপযুক্ত ফাংশনের মধ্যে থেকে সরাসরি DataStore-এ পড়া বা লেখা এড়িয়ে চলুন।

  1. ViewModel-এর মাধ্যমে DataStore এক্সপোজ করা। আপনার ViewModel-এ আপনার রেপোজিটরি (যা DataStore-কে র‍্যাপ করে) পাস করুন এবং Flow-কে StateFlow-এ কনভার্ট করুন যাতে UI এটি অবজার্ভ করতে পারে, যেমনটি নিম্নলিখিত স্নিপেটে দেখানো হয়েছে:

    class SettingsViewModel(
        private val userPreferencesRepository: UserPreferencesRepository
    ) : ViewModel() {
    
        // Expose the DataStore flow as a StateFlow for Compose
        val userSettings: StateFlow<UserSettings> = userPreferencesRepository.userSettingsFlow
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = UserSettings.getDefaultInstance()
            )
    
        fun updateCounter(newValue: Int) {
            viewModelScope.launch {
                userPreferencesRepository.updateCounter(newValue)
            }
        }
    }
    
  2. আপনার কম্পোজ করার মতো আইটেম থেকে পর্যবেক্ষণ ও লেখা। আপনার UI-তে StateFlow নিরাপদে পর্যবেক্ষণ করতে collectAsStateWithLifecycle ব্যবহার করুন এবং নিম্নলিখিত স্নপেটে দেখানো মতো, লেখার কাজ ম্যানেজ করতে ViewModel ফাংশন কল করুন:

    @Composable
    fun SettingsScreen(
        viewModel: SettingsViewModel = viewModel()
    ) {
        // Safely collect the state
        val settings by viewModel.userSettings.collectAsStateWithLifecycle()
    
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = "Current counter: ${settings.counter}")
    
            Spacer(modifier = Modifier.height(8.dp))
    
            Button(onClick = { viewModel.updateCounter(settings.counter + 1) }) {
                Text("Increment Counter")
            }
        }
    }
    

মাল্টি-প্রসেস কোডে DataStore ব্যবহার করা

আপনি DataStore-কে কনফিগার করে বিভিন্ন প্রসেস জুড়ে একই ডেটা অ্যাক্সেস করতে পারবেন একই ডেটা কনসিস্টেন্সি প্রপার্টি সহ যা একটি প্রসেসের মধ্যে থেকে পাওয়া যায়। বিশেষত, DataStore নিম্নলিখিত প্রপার্টি প্রদান করে:

  • রিড অপারেশন শুধুমাত্র সেই ডেটা ফেরত দেয় যা ডিস্কে সেভ করা হয়েছে।
  • রাইট করার পরে কনসিস্টেন্সি রিড করা।
  • রাইট সিরিয়ালাইজ করা হয়।
  • রাইট করার সময় রিড কখনও ব্লক করা হয় না।

পরিষেবা ও অ্যাক্টিভিটি সহ একটি নমুনা অ্যাপ্লিকেশন বিবেচনা করুন যেখানে পরিষেবা একটি আলাদা প্রসেসে চলছে এবং পর্যায়ক্রমে DataStore আপডেট করে।

এই উদাহরণে JSON ডেটা স্টোর ব্যবহার করা হয়েছে, তবে আপনি Preferences বা Proto DataStore-ও ব্যবহার করতে পারেন।

@Serializable data class Time(val lastUpdateMillis: Long)

আপনার ডেটার ধরন কীভাবে পড়তে ও লিখতে হয় তা সিরিয়ালাইজার DataStore-কে জানায়। ভাল করে দেখে নিন যে আপনি সিরিয়ালাইজারের জন্য একটি ডিফল্ট ভ্যালু যোগ করেছেন কিনা, এটি তখনই ব্যবহার করা হবে যখন এখনও কোনও ফাইল তৈরি করা হয়নি। নিচে kotlinx.serialization ব্যবহার করে প্রয়োগ করার একটি উদাহরণ দেওয়া হল:

object TimeSerializer : Serializer<Time> {

    override val defaultValue: Time = Time(lastUpdateMillis = 0L)

    override suspend fun readFrom(input: InputStream): Time =
        try {
            Json.decodeFromString(Time.serializer(), input.readBytes().decodeToString())
        } catch (serialization: SerializationException) {
            throw CorruptionException("Unable to read Time", serialization)
        }

    override suspend fun writeTo(t: Time, output: OutputStream) {
        output.write(Json.encodeToString(Time.serializer(), t).encodeToByteArray())
    }
}

বিভিন্ন প্রসেস জুড়ে DataStore ব্যবহার করতে, আপনাকে অ্যাপ ও পরিষেবা কোড, দু'টির জন্যই MultiProcessDataStoreFactory ব্যবহার করে DataStore অবজেক্ট তৈরি করতে হবে:

val dataStore =
    MultiProcessDataStoreFactory.create(
        serializer = TimeSerializer,
        produceFile = { context.dataStoreFile("time.pb") },
        corruptionHandler = null,
    )

আপনার AndroidManifiest.xml-এ নিম্নলিখিত ব্যক্তিদের যোগ করুন:

<service
    android:name="com.example.datastore.snippets.TimestampUpdateService"
    android:exported="false"
    android:process=":service" />

পরিষেবাটি মাঝে মাঝে updateLastUpdateTime-এ কল করে, যা updateData ব্যবহার করে ডেটা স্টোরে লেখে।

suspend fun updateLastUpdateTime() {
    dataStore.updateData { time -> time.copy(lastUpdateMillis = System.currentTimeMillis()) }
}

ডেটা ফ্লো ব্যবহার করে পরিষেবা দ্বারা লেখা ভ্যালু অ্যাপটি পড়ে:

fun timeFlow(): Flow<Long> = dataStore.data.map { time -> time.lastUpdateMillis }

এখন, আমরা এইসব ফাংশনকে একসাথে MultiProcessDataStore নামের একটি ক্লাসে রাখতে এবং অ্যাপে ব্যবহার করতে পারি।

পরিষেবা কোড এখানে দেওয়া হল:

class TimestampUpdateService : Service() {
    val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    val multiProcessDataStore by lazy { MultiProcessDataStore(applicationContext) }


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        serviceScope.launch {
            while (true) {
                multiProcessDataStore.updateLastUpdateTime()
                delay(1000)
            }
        }
        return START_NOT_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        serviceScope.cancel()
    }
}

এবং অ্যাপ কোড:

val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val multiProcessDataStore = remember(context) { MultiProcessDataStore(context) }

// Display time written by other process.
val lastUpdateTime by
    multiProcessDataStore
        .timeFlow()
        .collectAsState(initial = 0, coroutineScope.coroutineContext)
Text(text = "Last updated: $lastUpdateTime", fontSize = 25.sp)

DisposableEffect(context) {
    val serviceIntent = Intent(context, TimestampUpdateService::class.java)
    context.startService(serviceIntent)
    onDispose { context.stopService(serviceIntent) }
}

আপনি Hilt ডিপেন্ডেন্সি ইনজেকশন ব্যবহার করতে পারেন যাতে আপনার DataStore ইনস্ট্যান্স প্রসেস পিছু অনন্য হয়:

@Provides
@Singleton
fun provideDataStore(@ApplicationContext context: Context): DataStore<Settings> =
   MultiProcessDataStoreFactory.create(...)

ফাইল করাপশন ম্যানেজ করা

খুবই কম ক্ষেত্রে, DataStore-এর পারসিস্টেন্ট অন-ডিস্ক ফাইল কোরাপ্ট হয়ে যেতে পারে। সাধারণত, DataStore অটোমেটিক করাপশন থেকে রিকভার করে না, এবং এটি থেকে রিড করার চেষ্টা করলে সিস্টেম একটি CorruptionException দেখাবে।

DataStore-এ একটি করাপশন হ্যান্ডলার API আছে যা এই ধরনের পরিস্থিতিতে আপনাকে সহজে ডেটা ফিরিয়ে আনতে এবং ব্যতিক্রম এড়াতে সাহায্য করতে পারে। কনফিগার করা হলে, করাপশন হ্যান্ডলার করাপ্ট ফাইলটিকে একটি নতুন ফাইল দিয়ে পরিবর্তন করে দেয়, যার মধ্যে আগে থেকে সংজ্ঞায়িত ডিফল্ট ভ্যালু থাকে।

এই হ্যান্ডলার সেট-আপ করতে, by dataStore-এ বা DataStoreFactory ফ্যাক্টরি মেথডে DataStore ইনস্ট্যান্স তৈরি করার সময় একটি corruptionHandler দিন:

val dataStore: DataStore<Settings> = DataStoreFactory.create(
   serializer = SettingsSerializer(),
   produceFile = {
       File("${context.filesDir.path}/myapp.preferences_pb")
   },
   corruptionHandler = ReplaceFileCorruptionHandler { Settings(lastUpdate = 0) }
)

ডিভাইসের ব্যাক-আপ ও ফিরিয়ে আনা

Preferences DataStore ফাইল (*.preferences_pb) এবং Proto DataStore ফাইল অ্যাপের files/datastore/ ডিরেক্টরিতে স্টোর করা হয়। ডিফল্ট হিসেবে, এইসব ফাইল Android অটোমেটিক ব্যাক-আপ ও ডিভাইস-টু-ডিভাইস (D2D) ট্রান্সফারে অন্তর্ভুক্ত থাকে।

DataStore-এর জন্য ব্যাক-আপ সংক্রান্ত নিয়ম কনফিগার করা

আপনার DataStore-এ সংবেদনশীল ডেটার পাশাপাশি সংবেদনশীল নয় এমন পছন্দ (যেমন, ব্যবহারকারীর থিম বা ফিচার ফ্ল্যাগ) থাকলে, সেগুলিকে আলাদা আলাদা DataStore ফাইলে ভাগ করুন এবং res/xml/data_extraction_rules.xmlকনফিগার করুন:

<data-extraction-rules>
    <cloud-backup>
        <!-- Include general settings -->
        <include domain="file" path="datastore/user_settings.preferences_pb"/>
        <!-- Exclude sensitive local state -->
        <exclude domain="file" path="datastore/secure_state.preferences_pb"/>
    </cloud-backup>
    <device-to-device>
        <!-- Transfer settings during device-to-device transfer -->
        <include domain="file" path="datastore/"/>
    </device-to-device>
</data-extraction-rules>

মতামত জানান

এইসব রিসোর্সের মাধ্যমে আপনার মতামত ও আইডিয়া আমাদের সাথে শেয়ার করুন:

সমস্যা ট্র্যাকার:
সমস্যার ব্যাপারে অভিযোগ জানান যাতে আমরা বাগ ঠিক করতে পারি।

অতিরিক্ত রিসোর্স

Jetpack DataStore সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্স দেখুন:

নমুনা

ব্লগ

কোডল্যাবস