ডেটাস্টোর অ্যান্ড্রয়েড জেটপ্যাকের একটি অংশ।
জেটপ্যাক ডেটাস্টোর হলো একটি ডেটা স্টোরেজ সলিউশন যা আপনাকে প্রোটোকল বাফার ব্যবহার করে কী-ভ্যালু পেয়ার বা টাইপড অবজেক্ট সংরক্ষণ করতে দেয়। ডেটাস্টোর অ্যাসিঙ্ক্রোনাসলি, কনসিস্টেন্টলি এবং ট্রানজ্যাকশনালি ডেটা সংরক্ষণের জন্য কোটলিন কো-রুটিন এবং ফ্লো ব্যবহার করে।
আপনি যদি ডেটা সংরক্ষণের জন্য SharedPreferences ব্যবহার করে থাকেন, তাহলে এর পরিবর্তে DataStore-এ স্থানান্তরিত হওয়ার কথা বিবেচনা করুন।
ডেটাস্টোর এপিআই
DataStore ইন্টারফেসটি নিম্নলিখিত API প্রদান করে:
ডেটাস্টোর থেকে ডেটা পড়ার জন্য ব্যবহারযোগ্য একটি প্রবাহ।
val data: Flow<T>ডেটাস্টোরে ডেটা আপডেট করার একটি ফাংশন।
suspend updateData(transform: suspend (t) -> T)
ডেটাস্টোর কনফিগারেশন
আপনি যদি কী (key) ব্যবহার করে ডেটা সংরক্ষণ ও অ্যাক্সেস করতে চান, তাহলে প্রেফারেন্সেস ডেটাস্টোর (Preferences DataStore) ইমপ্লিমেন্টেশনটি ব্যবহার করুন, যার জন্য কোনো পূর্বনির্ধারিত স্কিমার প্রয়োজন হয় না এবং এটি টাইপ সেফটি (type safety) প্রদান করে না। এটির একটি SharedPreferences -এর মতো এপিআই (API) রয়েছে, কিন্তু শেয়ার্ড প্রেফারেন্সেসের সাথে যুক্ত অসুবিধাগুলো এতে নেই।
ডেটাস্টোর আপনাকে কাস্টম ক্লাস সংরক্ষণ করার সুযোগ দেয়। এটি করার জন্য, আপনাকে ডেটার জন্য একটি স্কিমা নির্ধারণ করতে হবে এবং সেটিকে সংরক্ষণযোগ্য ফরম্যাটে রূপান্তর করার জন্য একটি Serializer প্রদান করতে হবে। আপনি প্রোটোকল বাফার, 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এর একাধিক ইনস্ট্যান্স তৈরি করবেন না। এমনটা করলে DataStore-এর সমস্ত কার্যকারিতা নষ্ট হয়ে যেতে পারে। যদি একই প্রসেসে কোনো নির্দিষ্ট ফাইলের জন্য একাধিক DataStore সক্রিয় থাকে, তাহলে ডেটা পড়া বা আপডেট করার সময় DataStoreIllegalStateExceptionথ্রো করবে।DataStore<T>এর জেনেরিক টাইপ অবশ্যই অপরিবর্তনীয় হতে হবে। DataStore-এ ব্যবহৃত কোনো টাইপ পরিবর্তন করলে DataStore-এর প্রদত্ত সামঞ্জস্যতা নষ্ট হয়ে যায় এবং সম্ভাব্য গুরুতর, সহজে ধরা যায় না এমন বাগ তৈরি হয়। আমরা আপনাকে প্রোটোকল বাফার ব্যবহার করার পরামর্শ দিই, যা অপরিবর্তনীয়তা, একটি সুস্পষ্ট API এবং কার্যকর সিরিয়ালাইজেশন নিশ্চিত করতে সাহায্য করে।একই ফাইলের জন্য
SingleProcessDataStoreএবংMultiProcessDataStoreএর ব্যবহার একসাথে করবেন না । যদি আপনি একাধিক প্রসেস থেকেDataStoreঅ্যাক্সেস করতে চান, তবে আপনাকে অবশ্যইMultiProcessDataStoreব্যবহার করতে হবে।
ডেটা সংজ্ঞা
পছন্দ ডেটাস্টোর
এমন একটি কী নির্ধারণ করুন যা ডিস্কে ডেটা সংরক্ষণের জন্য ব্যবহৃত হবে।
val EXAMPLE_COUNTER = intPreferencesKey("example_counter")
JSON ডেটাস্টোর
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>(
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(t)
.encodeToByteArray()
)
}
}
প্রোটো ডেটাস্টোর
প্রোটো ডেটাস্টোর ইমপ্লিমেন্টেশনটি টাইপড অবজেক্টগুলোকে ডিস্কে সংরক্ষণ করার জন্য ডেটাস্টোর এবং প্রোটোকল বাফার ব্যবহার করে।
Proto DataStore-এর জন্য app/src/main/proto/ ডিরেক্টরিতে থাকা একটি proto ফাইলে একটি পূর্বনির্ধারিত স্কিমা প্রয়োজন। এই স্কিমাটি আপনার Proto DataStore-এ সংরক্ষণ করা অবজেক্টগুলোর টাইপ নির্ধারণ করে। প্রোটো স্কিমা নির্ধারণ সম্পর্কে আরও জানতে, protobuf ল্যাঙ্গুয়েজ গাইড দেখুন।
src/main/proto ফোল্ডারের ভিতরে settings.proto নামে একটি ফাইল যোগ করুন:
syntax = "proto3";
option java_package = "com.example.datastore.snippets.proto";
option java_multiple_files = true;
message Settings {
int32 example_counter = 1;
}
এমন একটি ক্লাস সংজ্ঞায়িত করুন যা 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)
}
}
একটি ডেটাস্টোর তৈরি করুন
ডেটা সংরক্ষণের জন্য ব্যবহৃত ফাইলটির একটি নাম নির্দিষ্ট করতে হবে।
পছন্দ ডেটাস্টোর
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<T> এর একটি ইনস্ট্যান্স তৈরি করুন, যেখানে T হলো সিরিয়ালাইজেবল ডেটা ক্লাস। আপনার কোটলিন ফাইলের টপ লেভেলে এটিকে একবার কল করুন এবং আপনার অ্যাপের বাকি অংশে এই প্রপার্টি ডেলিগেটের মাধ্যমে এটি অ্যাক্সেস করুন। fileName প্যারামিটারটি DataStore-কে বলে দেয় ডেটা সংরক্ষণের জন্য কোন ফাইলটি ব্যবহার করতে হবে, এবং serializer প্যারামিটারটি DataStore-কে পূর্বে সংজ্ঞায়িত সিরিয়ালাইজার ক্লাসের নাম বলে দেয়।
val Context.dataStore: DataStore<Settings> by dataStore(
fileName = "settings.json",
serializer = SettingsSerializer,
)
প্রোটো ডেটাস্টোর
dataStore দ্বারা তৈরি প্রপার্টি ডেলিগেট ব্যবহার করে DataStore<T> এর একটি ইনস্ট্যান্স তৈরি করুন, যেখানে T হলো প্রোটো ফাইলে সংজ্ঞায়িত টাইপ। আপনার কোটলিন ফাইলের টপ লেভেলে এটিকে একবার কল করুন এবং আপনার অ্যাপের বাকি অংশে এই প্রপার্টি ডেলিগেটের মাধ্যমে এটি অ্যাক্সেস করুন। fileName প্যারামিটারটি DataStore-কে বলে দেয় ডেটা সংরক্ষণের জন্য কোন ফাইলটি ব্যবহার করতে হবে, এবং serializer প্যারামিটারটি DataStore-কে পূর্বে সংজ্ঞায়িত সিরিয়ালাইজার ক্লাসের নাম বলে দেয়।
val Context.dataStore: DataStore<Settings> by dataStore(
fileName = "settings.pb",
serializer = SettingsSerializer,
)
ডেটাস্টোর থেকে পড়ুন
ডেটা সংরক্ষণের জন্য ব্যবহৃত ফাইলটির একটি নাম নির্দিষ্ট করতে হবে।
পছন্দ ডেটাস্টোর
যেহেতু প্রেফারেন্সেস ডেটাস্টোর কোনো পূর্বনির্ধারিত স্কিমা ব্যবহার করে না, তাই DataStore<Preferences> ইনস্ট্যান্সে সংরক্ষণ করার জন্য প্রয়োজনীয় প্রতিটি মানের জন্য একটি কী (key) নির্ধারণ করতে আপনাকে অবশ্যই সংশ্লিষ্ট কী টাইপ ফাংশন ব্যবহার করতে হবে। উদাহরণস্বরূপ, একটি int মানের জন্য কী নির্ধারণ করতে, intPreferencesKey ব্যবহার করুন। তারপর, একটি ফ্লো (Flow) ব্যবহার করে উপযুক্ত সংরক্ষিত মানটি প্রকাশ করতে DataStore.data প্রপার্টিটি ব্যবহার করুন।
fun counterFlow(): Flow<Int> = context.dataStore.data.map { preferences ->
preferences[EXAMPLE_COUNTER] ?: 0
}
JSON ডেটাস্টোর
আপনার সংরক্ষিত অবজেক্ট থেকে উপযুক্ত প্রপার্টির একটি Flow প্রকাশ করতে DataStore.data ব্যবহার করুন।
fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings ->
settings.exampleCounter
}
প্রোটো ডেটাস্টোর
আপনার সংরক্ষিত অবজেক্ট থেকে উপযুক্ত প্রপার্টির একটি Flow প্রকাশ করতে DataStore.data ব্যবহার করুন।
fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings ->
settings.exampleCounter
}
একটি কম্পোজেবল-এর মধ্যে থাকা ViewModel দ্বারা উৎপাদিত Flow ব্যবহার করতে collectAsStateWithLifecycle ব্যবহার করুন। এটি নিরাপদে ডেটাস্টোর ফ্লো-কে কম্পোজ স্টেটে রূপান্তরিত করে, যা রিকম্পোজিশন ট্রিগার করে।
@Composable
fun SomeScreen(counterFlow: Flow<Int>) {
val counter by counterFlow.collectAsStateWithLifecycle(initialValue = 0)
Text(text = "Example counter: ${counter}")
}
collectAsStateWithLifecycle সম্পর্কে আরও তথ্যের জন্য, State এবং Jetpack Compose দেখুন।
ডেটাস্টোরে লিখুন
DataStore-এ একটি updateData ফাংশন রয়েছে যা একটি সংরক্ষিত অবজেক্টকে ট্রানজ্যাকশনালি আপডেট করে। updateData আপনাকে আপনার ডেটা টাইপের একটি ইনস্ট্যান্স হিসাবে ডেটার বর্তমান অবস্থা প্রদান করে এবং একটি অ্যাটমিক রিড-রাইট-মডিফাই অপারেশনের মাধ্যমে ট্রানজ্যাকশনালি ডেটা আপডেট করে। updateData ব্লকের সমস্ত কোডকে একটি একক ট্রানজ্যাকশন হিসাবে গণ্য করা হয়।
পছন্দ ডেটাস্টোর
suspend fun incrementCounter() {
context.dataStore.updateData {
it.toMutablePreferences().also { preferences ->
preferences[EXAMPLE_COUNTER] = (preferences[EXAMPLE_COUNTER] ?: 0) + 1
}
}
}
JSON ডেটাস্টোর
suspend fun incrementCounter() {
context.dataStore.updateData { settings ->
settings.copy(exampleCounter = settings.exampleCounter + 1)
}
}
প্রোটো ডেটাস্টোর
suspend fun incrementCounter() {
context.dataStore.updateData { settings ->
settings.copy { exampleCounter = exampleCounter + 1 }
}
}
একটি কম্পোজ অ্যাপে ডেটাস্টোর ব্যবহার করুন
একটি Compose অ্যাপে DataStore ব্যবহার করতে, Android অ্যাপ আর্কিটেকচারের নির্দেশিকা অনুসরণ করুন। এর জন্য DataStore অপারেশনগুলিকে আপনার ডেটা লেয়ারে (যেমন একটি রিপোজিটরি) রাখুন এবং একটি ViewModel মাধ্যমে আপনার UI-তে ডেটা প্রকাশ করুন।
আপনার কম্পোজেবল ফাংশনগুলির মধ্যে সরাসরি ডেটাস্টোর থেকে পড়া বা তাতে লেখা এড়িয়ে চলুন।
একটি ViewModel-এর মাধ্যমে DataStore-কে উন্মুক্ত করুন। আপনার রিপোজিটরি (যা DataStore-কে আবৃত করে) আপনার
ViewModelএ পাস করুন এবং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) } } }আপনার কম্পোজেবল থেকে পর্যবেক্ষণ করুন এবং লিখুন। আপনার 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 নিম্নলিখিত বৈশিষ্ট্যগুলি প্রদান করে:
- রিড অপারেশনের মাধ্যমে শুধুমাত্র সেই ডেটা ফেরত আসে যা ডিস্কে সংরক্ষণ করা হয়েছে।
- রিড-আফটার-রাইট সামঞ্জস্য।
- রাইটগুলো ক্রমিকভাবে সম্পন্ন হয়।
- রাইটের কারণে রিড কখনো ব্লক হয় না।
একটি নমুনা অ্যাপ্লিকেশনের কথা বিবেচনা করুন, যেখানে একটি সার্ভিস এবং একটি অ্যাক্টিভিটি রয়েছে, এবং সার্ভিসটি একটি পৃথক প্রসেসে চলছে ও পর্যায়ক্রমে ডেটাস্টোর আপডেট করে।
এই উদাহরণে একটি JSON ডেটাস্টোর ব্যবহার করা হয়েছে, কিন্তু আপনি প্রেফারেন্সেস বা প্রোটো ডেটাস্টোরও ব্যবহার করতে পারেন।
@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>(
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(t)
.encodeToByteArray()
)
}
}
বিভিন্ন প্রসেসের মধ্যে DataStore ব্যবহার করতে হলে, অ্যাপ এবং সার্ভিস কোড উভয়ের জন্যই MultiProcessDataStoreFactory ব্যবহার করে DataStore অবজেক্টটি তৈরি করতে হবে:
val dataStore = MultiProcessDataStoreFactory.create(
serializer = TimeSerializer,
produceFile = {
File("${context.filesDir.path}/time.pb")
},
corruptionHandler = null
)
আপনার AndroidManifiest.xml এ নিম্নলিখিতটি যোগ করুন:
<service
android:name=".TimestampUpdateService"
android:process=":my_process_id" />
সার্ভিসটি পর্যায়ক্রমে 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(...)
ফাইলের দুর্নীতি মোকাবেলা করুন
এমন বিরল পরিস্থিতি দেখা যায় যেখানে ডেটাস্টোরের ডিস্কে থাকা স্থায়ী ফাইলটি ক্ষতিগ্রস্ত হতে পারে। ডিফল্টরূপে, ডেটাস্টোর স্বয়ংক্রিয়ভাবে এই ক্ষতি থেকে পুনরুদ্ধার হয় না, এবং এটি থেকে ডেটা পড়ার চেষ্টা করলে সিস্টেম একটি CorruptionException থ্রো করে।
DataStore একটি করাপশন হ্যান্ডলার এপিআই প্রদান করে যা আপনাকে এই ধরনের পরিস্থিতিতে সুষ্ঠুভাবে পুনরুদ্ধার করতে এবং এক্সেপশন থ্রো করা এড়াতে সাহায্য করতে পারে। কনফিগার করা হলে, করাপশন হ্যান্ডলারটি ত্রুটিপূর্ণ ফাইলটিকে একটি পূর্বনির্ধারিত ডিফল্ট মান সম্বলিত নতুন ফাইল দিয়ে প্রতিস্থাপন করে।
এই হ্যান্ডলারটি সেট আপ করতে, 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) }
)
মতামত দিন
এই মাধ্যমগুলোর মাধ্যমে আমাদের সাথে আপনার মতামত ও ধারণা শেয়ার করুন:
- ইস্যু ট্র্যাকার :
- সমস্যাগুলো জানান, যাতে আমরা বাগগুলো ঠিক করতে পারি।
অতিরিক্ত সম্পদ
Jetpack DataStore সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্সগুলো দেখুন:
নমুনা
ব্লগ
কোডল্যাবস
{% হুবহু %}আপনার জন্য প্রস্তাবিত
- দ্রষ্টব্য: জাভাস্ক্রিপ্ট বন্ধ থাকলেও লিঙ্কের লেখা প্রদর্শিত হয়।
- পৃষ্ঠা ডেটা লোড এবং প্রদর্শন করুন
- লাইভডেটা ওভারভিউ
- লেআউট এবং বাইন্ডিং এক্সপ্রেশন
