StateStore   Android Jetpack-এর অংশ।

StateStore হল একটি টাইপ-সেফ কন্টেনার যা আপনার অ্যাপ জুড়ে Compose State হিসেবে শেয়ার করা অ্যাপ্লিকেশন স্টেট স্টোর করে এবং দেখায়।

উদাহরণ

অ্যাপ্লিকেশন-স্কোপড StateStore তৈরি করে, আপনি একই প্রসেসের মধ্যে অ্যাপ্লিকেশন কম্পোনেন্টের মধ্যে স্টেট শেয়ার করতে পারবেন:

  • একাধিক অ্যাক্টিভিটি: আপনার অ্যাপ যদি একসাথে একাধিক অ্যাক্টিভিটি দেখায় (যেমন, ইমেল ক্লায়েন্টে ইনবক্স অ্যাক্টিভিটি ও এডিটর অ্যাক্টিভিটি) অথবা এমন কোনও অ্যাক্টিভিটি থাকে যা মাল্টি-ইনস্ট্যান্স (যেমন, ডকুমেন্ট ভিউয়ার অ্যাক্টিভিটি) সাপোর্ট করে, তাহলে আপনি তাদের মধ্যে তথ্য শেয়ার করতে StateStore ব্যবহার করতে পারেন।
  • অ্যাক্টিভিটি ও পরিষেবা: কোনও অ্যাক্টিভিটি ও ব্যাকগ্রাউন্ড CarAppService বা AppFunction-এর মধ্যে স্ট্যাটাস সিঙ্ক করুন।
  • অ্যাক্টিভিটি এবং কন্টেন্ট প্রোভাইডার বা উইজেট: কোনও অ্যাক্টিভিটি এবং হোম স্ক্রিন উইজেটের মধ্যে স্ট্যাটাস শেয়ার করুন।

যদি কোনও সিঙ্গলটনের শুধুমাত্র ইন-মেমরি State<T>-এর প্রয়োজন হয়, যেখানে কীড লুকআপ বা DataStore-ব্যাকড প্রসেস-ডেথ রিস্টোরেশনের প্রয়োজন নেই, তাহলে আপনি সরাসরি সিঙ্গলটনে mutableStateOf প্রপার্টি এক্সপোজ করতে পারেন। আপনার অ্যাপ জুড়ে স্টেট API-এর তুলনা করতে, আপনার আর্কিটেকচার জুড়ে সঠিক স্টেট API বেছে নিন দেখুন।

API ওভারভিউ

androidx.appstate.statestore প্যাকেজে StateStore এবং StateStoreKey ক্লাস প্রদান করা হয়:

package androidx.appstate.statestore

import androidx.compose.runtime.State
import kotlinx.serialization.Serializable

public class StateStore {
    public val keys: Set<StateStoreKey<*>>
    public fun <T> getState(
        stateKey: StateStoreKey<T>,
        defaultValue: T = stateKey.defaultValue,
    ): State<T>
    public fun <T> setState(stateKey: StateStoreKey<T>, value: T)
    public inline fun <T> updateState(
        stateKey: StateStoreKey<T>,
        defaultValue: T = stateKey.defaultValue,
        update: (T) -> T,
    )
}

@Serializable
public open class StateStoreKey<T>(
    public val defaultValue: T,
)

আপনার রাজ্য উল্লেখ করুন

ভ্যালু স্টোর ও রিট্রিভ করার সময় টাইপ নিরাপত্তা নিশ্চিত করতে, StateStore StateStoreKey ক্লাস ব্যবহার করে ভ্যালু রিড ও রাইট করার জন্য ব্যবহৃত কীগুলি সংজ্ঞায়িত করে। StateStoreKey সংজ্ঞা private বা internal ম্যানেজার, রিপোজিটরি বা সেই স্লাইস অফ স্টেটের মালিকানা আছে এমন মডিউলে রাখুন:

@Serializable
sealed interface FocusSession {
    @Serializable
    data object Idle : FocusSession

    @Serializable
    data class Running(
        val taskId: String,
        val endTimeMillis: Long,
    ) : FocusSession

    @Serializable
    data class Paused(
        val taskId: String,
        val remainingMillis: Long,
    ) : FocusSession
}

@Serializable
private data object FocusSessionKey :
    StateStoreKey<FocusSession>(defaultValue = FocusSession.Idle)

StateStore ইনস্ট্যান্স তৈরি ও ইনজেক্ট করুন

StateStore হল একটি সাধারণ ক্লাস যা আপনি অ্যাপ্লিকেশন বা মডিউল স্কোপে একবার ইনস্ট্যান্টিয়েট করেন (যেমন, আপনার Application ক্লাস বা ডিপেন্ডেন্সি ইনজেকশন মডিউলে) এবং ম্যানেজার বা রিপোজিটরিতে ইনজেক্ট করেন যা স্টেট রিড ও রাইট করে, UI ক্লাসে সরাসরি StateStore দেখানোর পরিবর্তে:

// Instantiate at the application or DI module level
val stateStore = StateStore()

// Inject into managers or repositories that encapsulate their own keys
class FocusSessionManager(
    private val stateStore: StateStore,
)

স্ট্যাটাস দেখুন ও লিখুন

আপনার ম্যানেজার বা রিপোজিটরির মধ্যে, আপনার ব্যক্তিগত StateStoreKey সংজ্ঞা ব্যবহার করে ইনজেক্ট করা StateStore-এ ভ্যালু পড়ুন, লিখুন এবং আপডেট করুন এবং কলারদের জন্য শুধুমাত্র পড়ার জন্য State<T> প্রপার্টি এবং মিউটেশন ফাংশন প্রকাশ করুন।

স্ট্যাটাস পড়ুন

State<T> অবজেক্ট পুনরুদ্ধার করতে getState(stateKey, defaultValue) ব্যবহার করুন। 'কী' এখনও ইনিশিয়ালাইজ করা না হলে, StateStore এটি defaultValue প্যারামিটার দিয়ে পপুলেট করে, যা ডিফল্ট হিসেবে stateKey.defaultValue (অথবা আপনি পপুলেট না করা 'কী' ইনিশিয়ালাইজ করার সময় কাস্টম defaultValue পাস করতে পারেন)। যেহেতু getState একটি State<T>, ViewModels, UI কম্পোজেবল, উইজেট এবং transform ব্লক রিটার্ন করে, তাই ম্যানেজারের প্রপার্টি প্রতিক্রিয়াশীলভাবে পড়তে পারে:

class FocusSessionManager(
    private val stateStore: StateStore,
) {
    val session: State<FocusSession> = stateStore.getState(FocusSessionKey)
}

class FocusTimerViewModel(
    focusSessionManager: FocusSessionManager,
) : ViewModel() {
    val session: State<FocusSession> = focusSessionManager.session
}

@Composable
fun FocusBanner(viewModel: FocusTimerViewModel = viewModel()) {
    // Reads state reactively; recomposes when FocusSessionKey updates
    when (val session = viewModel.session.value) {
        FocusSession.Idle -> Text(text = "No active focus session")
        is FocusSession.Running -> Text(text = "Focusing on ${session.taskId}")
        is FocusSession.Paused -> Text(text = "Paused: ${session.taskId}")
    }
}

রাজ্য লিখুন

আপনার ম্যানেজারের মধ্যে setState(stateKey, value) ব্যবহার করে কোনও কী-এর সাথে যুক্ত ভ্যালু শুরু করুন বা পরিবর্তন করুন:

class FocusSessionManager(
    private val stateStore: StateStore,
) {
    val session: State<FocusSession> = stateStore.getState(FocusSessionKey)

    fun startFocus(taskId: String, endTimeMillis: Long) {
        stateStore.setState(
            FocusSessionKey,
            FocusSession.Running(
                taskId = taskId,
                endTimeMillis = endTimeMillis,
            ),
        )
    }

    fun endFocus() {
        stateStore.setState(FocusSessionKey, FocusSession.Idle)
    }
}

রাজ্য আপডেট করুন

বর্তমান ভ্যালুর উপর ভিত্তি করে কোনও স্টেট আপডেট করতে হলে, updateState ব্যবহার করুন। এটি বর্তমান ভ্যালু ফিরিয়ে আনে (অথবা সেট করা না থাকলে ডিফল্ট ভ্যালু ব্যবহার করে) এবং আপনার আপডেট ল্যাম্বডা প্রয়োগ করে:

class FocusSessionManager(
    private val stateStore: StateStore,
) {
    val session: State<FocusSession> = stateStore.getState(FocusSessionKey)

    fun pauseFocus(nowMillis: Long) {
        stateStore.updateState(FocusSessionKey) { current ->
            if (current is FocusSession.Running) {
                FocusSession.Paused(
                    taskId = current.taskId,
                    remainingMillis = (current.endTimeMillis - nowMillis)
                        .coerceAtLeast(0L),
                )
            } else {
                current
            }
        }
    }

    fun resumeFocus(nowMillis: Long) {
        stateStore.updateState(FocusSessionKey) { current ->
            if (current is FocusSession.Paused) {
                FocusSession.Running(
                    taskId = current.taskId,
                    endTimeMillis = nowMillis + current.remainingMillis,
                )
            } else {
                current
            }
        }
    }
}

ইন্টিগ্রেশন

প্রসেস বন্ধ করা এবং অ্যাপ রিস্টার্ট করার সময় স্ট্যাটাস বজায় রাখতে ও রিস্টোর করতে StateStore, Jetpack DataStore-এর সাথে ইন্টিগ্রেট করে।

DataStore

androidx.appstate.statestore:statestore-datastore আর্টিফ্যাক্ট আপনাকে শেয়ার করা StateStore ইনস্ট্যান্সে একবার পারসিস্টেন্স কনফিগার করতে দেয় যাতে যেকোনও ম্যানেজারের পারসিস্টেড 'কী' অটোমেটিক সেভ হয় এবং DataStore ব্যবহার করে ডিস্ক থেকে রিস্টোর হয়।

androidx.appstate.datastore প্যাকেজ নিম্নলিখিত API প্রদান করে:

package androidx.appstate.datastore

import androidx.appstate.statestore.StateStore
import androidx.datastore.core.DataStore
import kotlinx.coroutines.CoroutineScope

public interface PersistToDataStore

public suspend fun StateStore.syncToDataStore(
    path: String,
    coroutineScope: CoroutineScope,
)

public suspend fun StateStore.syncToDataStore(
    dataStore: DataStore<StateStorePreferences>,
)
  1. PersistToDataStore প্রয়োগ করুন: PersistToDataStore ইন্টারফেস প্রয়োগ করে যেসব StateStoreKey বজায় রাখা উচিত সেগুলি চিহ্নিত করুন:

@Serializable
private data object FocusSessionKey :
    StateStoreKey<FocusSession>(defaultValue = FocusSession.Idle),
    PersistToDataStore

  1. DataStore-এ StateStore বাইন্ড করুন: আপনার শেয়ার করা StateStore ইনস্ট্যান্স সেট-আপ করার সময় একবার syncToDataStore কল করুন (যেমন, আপনার Application ক্লাস বা ডিপেন্ডেন্সি ইনজেকশন মডিউলে)। যেহেতু syncToDataStore হল একটি suspend ফাংশন যা ডিস্ক থেকে সেভ করা ভ্যালু রিস্টোর করতে এবং প্রদত্ত coroutineScope-এ ভবিষ্যতের পরিবর্তনগুলি সেভ করা চালিয়ে যেতে অনির্দিষ্টকালের জন্য সাসপেন্ড করে, তাই এটিকে launch-এর মধ্যে কল করুন এবং আপনার অ্যাপ্লিকেশন-লেভেল CoroutineScope পাস করুন। চালু করার সময়, getState প্রথমে মেমরিতে defaultValue ফিরিয়ে আনে এবং ডিস্ক থেকে DataStore-এর রিডিং শেষ হলে State আপডেট করে:

class ProductivityApplication : Application() {
    val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)

    val stateStore = StateStore().also { store ->
        // Restore saved values and automatically persist future changes
        // for all PersistToDataStore keys across managers
        applicationScope.launch {
            store.syncToDataStore(
                path = dataStoreFile("statestore.json").absolutePath,
                coroutineScope = applicationScope,
            )
        }
    }

    val focusSessionManager = FocusSessionManager(stateStore)
}

DataStore পারসিসটেন্স সংক্রান্ত নির্দেশিকা

যেহেতু syncToDataStore সিরিয়ালাইজ করে এবং যখনই PersistToDataStore কী-এর ভ্যালু পরিবর্তন হয় তখনই ডিস্কে লেখে, তাই কী এবং কখন পারসিস্ট করতে হবে তা বেছে নেওয়ার সময় এইসব নির্দেশিকা অনুসরণ করুন:

  • প্রতিটি টাইমার টিকের পরিবর্তে শুরু বা শেষের টাইমস্ট্যাম্প সেভ করুন: টাইমার বা প্লেব্যাক প্রগ্রেসের জন্য, প্রতি সেকেন্ড বা ফ্রেমে PersistToDataStore কী আপডেট করার পরিবর্তে একটি স্থিতিশীল রেফারেন্স ভ্যালু (যেমন endTimeMillis বা startedAtMillis) বজায় রাখুন এবং UI-তে লাইভ অতিবাহিত বা অবশিষ্ট ডিসপ্লে গণনা করুন।
  • পারসিস্টেড কী আপডেট করার আগে ব্যবহারকারীর দ্রুত ইনপুট ডিবাউন্স করুন: টেক্সট ড্রাফ্ট, সার্চ কোয়েরি বা স্লাইডারের জন্য, ইন-মেমরি MutableState (বা StateStoreKey যা PersistToDataStore প্রয়োগ করে না) -এ অবিলম্বে ইনপুট হোল্ড করুন এবং ইনপুট সেটেল হওয়ার পরে পারসিস্টেড StateStoreKey-এ শুধুমাত্র setState কল করুন।
  • পারসিস্টেড 'কী' লাইটওয়েট রাখুন: প্রতিটি আপডেটে একটি ফাইলে StateStore-এর সব PersistToDataStore 'কী' একসাথে সিরিয়ালাইজ করা হয়। কমপ্যাক্ট সেশন স্টেট—যেমন অ্যাক্টিভ আইডি, ফিল্টার সিলেকশন বা প্রোগ্রেসে থাকা ফর্ম ড্রাফ্ট—সেভ করে রাখুন এবং Room-এ বড় কালেকশন বা কোয়েরি করা যায় এমন ডেটাসেট রাখুন।