কয়েক বছর আগে, Google DataStore ঘোষণা করেছিল, যা היা SharedPreferences-এর প্রতিস্থাপন।
আপনি যদি আপনার অ্যাপ্লিকেশনে SharedPreferences ব্যবহার করেন বা করতেন, তবে আপনি স্যুইচ করার কথা চিন্তা করতে পারেন। কিন্তু সবকিছুর মতো, এখানে মূল প্রশ্ন: ডেভেলপমেন্ট খরচ কত হবে?
DataStore ব্যবহার করার সুবিধা রয়েছে, কিন্তু শুধু Proto DataStore আপনাকে অবজেক্ট সংরক্ষণ করতে দেয় টাইপ সেফটি দিয়ে।
আপনি যদি Proto DataStore-এর ডকুমেন্টেশন দেখেন, তবে আপনি পাবেন এটি কিছুটা পুরনো এবং এটির সাথে কাজ করার কিছু গুরুত্বপূর্ণ ধাপ অনুপস্থিত। তাই এই আর্টিকেলে, আমরা Proto DataStore আপনার অ্যাপ্লিকেশনে কীভাবে ইন্টিগ্রেট করবেন এবং দেখাবো যে এটি ব্যবহার করা সেটা বড় ঝামেলা নয়।
DataStore কী?
Jetpack DataStore-এর দুটি ভেরিয়েন্ট রয়েছে:
- Preferences DataStore
- Proto DataStore
আমরা প্রথমটিতে আলোচনা করব না, SharedPreferences-এর সাথে এর সাদৃশ্যের কারণে এবং সেটি وسیعی কভার করা হয়েছে। এখন চলুন বুঝি Proto DataStore-এ Proto কী বোঝায়।
Proto হলো Google এনামকরণ করা নাম Protocol Buffersকে প্রতিনিধিত্ব করার জন্য। এগুলো (Google-এর) একটি মেকানিজম যা আপনাকে স্ট্রাকচার্ড ডেটা সিরিয়ালাইজ করতে সাহায্য করে। এগুলো কোডিং ল্যাঙ্গুয়েজ-স্পেসিফিক নয় এবং সাধারণত, আপনি যে ডেটা টাইপের সাথে কাজ করতে চান সেটি ডিফাইন করেন এবং তারপর কোড জেনারেট হয় যা আপনাকে আপনার ডেটা পড়তে এবং লিখতে সাহায্য করে।
✋ আমরা এই আর্টিকেলে Proto 3 ভার্সন ব্যবহার করব।
সেটি কীভাবে দেখায়?
message MyItem { string itemName = 1; int32 itemId = 2; }
প্রথমে, আপনি message কীওয়ার্ড দিয়ে একটি অবজেক্ট ডিফাইন করেন। এর ভিতরে, আপনি সেই অবজেক্টের সাথে যুক্ত ফিল্ডগুলো লিস্ট করেন। প্রতিটি ফিল্ডের শেষে থাকা নম্বরগুলো ফিল্ডটিকে আইডেন্টিফাই করতে ব্যবহৃত হয় এবং একবার সেট হলে এবং অবজেক্টটি ব্যবহারে থাকলে পরিবর্তন করা যাবে না।
কিন্তু যদি আমরা আমাদের .proto ফাইলে একাধিক অবজেক্ট রাখতে চাই? ধরে নিলে অবজেক্টগুলো একে অপরের সাথে সম্পর্কিত, আপনি এটি সহজে করতে পারেন আরও message অবজেক্ট যোগ করে:
message MyItem { string itemName = 1; int32 itemId = 2; } message MyListOfItems { repeated MyItem items = 1; }
উপরে লক্ষ্য করুন আমরা একটি আরো message অবজেক্ট যোগ করেছি যা উপরে ডিফাইন করা MyItem অবজেক্টের ওপর নির্ভরশীল। আপনি যদি অবজেক্টের একটি লিস্ট ডিফাইন করতে চান, তবে আপনাকে repeated কীওয়ার্ড ব্যবহার করতে হবে।
Proto DataStore সেট আপ করার উপায়
শুরু করতে, আপনাকে নিচের ডিপেন্ডেন্সিগুলো আপনার অ্যাপ্লিকেশন লেভেল build.gradle-এ যোগ করতে হবে:
implementation "androidx.datastore:datastore-preferences:1.0.0" implementation "com.google.protobuf:protobuf-javalite:3.18.0"
তারপর, আপনাকে আপনার প্রজেক্টে একটি proto ডিরেক্টরি তৈরি করতে হবে। এই ডিরেক্টরিটি আপনার প্রজেক্ট স্ট্রাকচারে Java ফোল্ডারের সিবলিং হতে হবে।
proto ডিরেক্টরির ভিতরে, আপনি একটি .proto ফাইল তৈরি করবেন। এই ফাইলটি Proto DataStore-এ আপনি যে ডেটা টাইপগুলো সংরক্ষণ করতে চান সেগুলো জেনারেট করার জন্য দায়িত্বশীল।
proto ডিরেক্টরির ভিতরে, .proto এক্সটেনশন সহ একটি ফাইল তৈরি করুন। আমাদের .proto ফাইলটি একটি Todo লিস্টকে প্রতিনিধিত্ব করার অবজেক্ট ধারণ করবে (আর কী?). তাই আমরা আমাদের ফাইলকে todo.proto নাম দিব এবং সেটি এমন দেখাবে:
syntax = "proto3"; option java_package = "com.yourPackageName.todo"; option java_multiple_files = true; message TodoItem { string itemId = 1; string itemDescription = 2; } message TodoItems { repeated TodoItem items = 1; }
লক্ষ্য করুন কীভাবে আমরা দুটি message অবজেক্ট ডিফাইন করেছি:
- TodoItem – যা একটি টুডু আইটেম ডিফাইন করে
- TodoItems – যা TodoItem অবজেক্টের একটি লিস্ট ডিফাইন করে
এরপর, প্রজেক্ট বিল্ড করুন যাতে TodoItem এবং TodoItems-এর জন্য ক্লাসগুলো জেনারেট হয়।
আমাদের ডেটা অবজেক্টগুলো ডিফাইন হলে, আমাদের সেগুলো সিরিয়ালাইজ করার একটি ক্লাস তৈরি করতে হবে। এই ক্লাসটি DataStore-কে বলবে কীভাবে আমাদের অবজেক্টগুলো পড়তে/লিখতে হবে।
// 1 object TodoItemSerializer: Serializer<TodoItems> { // 2 override val defaultValue: TodoItems = TodoItems.getDefaultInstance() // 3 override suspend fun readFrom(input: InputStream): TodoItems { try { return TodoItems.parseFrom(input) } catch (exception: InvalidProtocolBufferException) { throw CorruptionException("Cannot read proto.", exception) } } // 3 override suspend fun writeTo( t: TodoItems, output: OutputStream ) = t.writeTo(output) }
আমরা এই ক্লাসে কী কী আছে সেটি রিভিউ করি:
- যখন আমরা ক্লাস ডিক্লেয়ার করি, আপনাকে Serializer ইন্টারফেস ইমপ্লিমেন্ট করতে হবে আমাদের অবজেক্ট হিসেবে টাইপ (T) দিয়ে
- সিরিয়ালাইজারের জন্য একটি ডিফল্ট ভ্যালু ডিফাইন করুন যদি ফাইল তৈরি না হয়
- readFrom/writeTo মেথডগুলো ওভাররাইড করুন এবং নিশ্চিত করুন আমাদের অবজেক্ট সেটি ডেটা টাইপ হিসেবে আছে সেখানে
আমাদের .proto ফাইল আছে আমাদের ডেটা টাইপসহ এবং আমাদের সিরিয়ালাইজার, তাই পরবর্তী ধাপ হলো DataStore ইনস্ট্যানশিয়েট করা। আমরা এটি করি dataStore দ্বারা তৈরি প্রপার্টি ডেলিগেট ব্যবহার করে, যেটি একটি ফাইলনেম চায় যেখানে আমাদের ডেটা সংরক্ষিত হবে এবং আমাদের সিরিয়ালাইজার ক্লাস (যেটি আমরা উপরে ডিফাইন করেছি)।
private const val DATA_STORE_FILE_NAME = "todo.pb" private val Context.todoItemDatastore: DataStore<TodoItems> by dataStore( fileName = DATA_STORE_FILE_NAME, serializer = TodoItemSerializer, )
এই কোডের টুকরোটি আপনার পছন্দের একটি ক্লাসের শীর্ষে থাকতে হবে ক্লাস ডেফিনিশনের উপরে। অর্থাৎ:
private const val DATA_STORE_FILE_NAME = "todo.pb" private val Context.todoItemDatastore: DataStore<TodoItems> by dataStore( fileName = DATA_STORE_FILE_NAME, serializer = TodoItemSerializer, ) class YourClassName { }
এই অবজেক্টটি আমাদের অ্যাপ্লিকেশনের বাকি অংশে এক্সেস করতে, আমাদের একটি কনটেক্সট ব্যবহার করতে হবে। একটি উদাহরণ হলো আপনার ভিউমডেল ক্লাসে অ্যাপ্লিকেশন কনটেক্সট ব্যবহার করা:
class MyViewModel(application: Application): AndroidViewModel(application) { val todoDataStore = application.todoItemDataStore //... }
Kotlin Flow কীভাবে ব্যবহার করবেন
এখন যেহেতু আমরা DataStore-র জন্য প্রয়োজন সবকিছু সেট আপ করার মাধ্যমে যেছি, আমরা আলোচনা করব কীভাবে আমরা আসলে এর সাথে ইন্টারঅ্যাক্ট করতে যাচ্ছি। আমরা ডেটা পড়তে এবং লিখতে চাইব এটিতে থেকে/এটিতে। কিন্তু আমরা সেটি করার উপায় ভিন্ন সেটা যা আপনি SharedPreferences থেকে অভ্যস্ত হতে পারেন।
উপরে ডিফাইন করা DataStore-র একটি data ফিল্ড রয়েছে যা আমাদের DataStore-এ ডিফাইন করা প্রপার্টিগুলোর জন্য একটি Flow এক্সপোজ করে।
🚰 আপনি যদি flows সাথে পরিচিত নন, এটি শুরু করার একটি ভালো জায়গা।
val todoItemFlow: Flow<TodoItems> = todoItemDataStore.data .catch { exception -> if (exception is IOException) { emit(TodoItems.getDefaultInstance()) } else { throw exception } }
উপরের কোডটি দেখায় কীভাবে আপনি একটি Flow ডিফাইন করতে পারেন যা Proto DataStore থেকে ডেটা কালেক্ট করে। একটি catch ব্লক যোগ করা হয়েছে এক্সসেপশন হলে। আপনি এই লজিকটি সেটি ক্লাসে রাখতে পারেন যেখানে আপনি আপনার DataStore ডিফাইন করেছেন এবং ভিউমডেলে এরকম ব্যবহার করতে পারেন:
val todoItemsFlow: LiveData<TodoItems> = todoItemsRepository.todoItemFlow.asLiveData()
লক্ষ্য করুন কীভাবে আমরা আমাদের Flow কে LiveData-এ কনভার্ট করলাম। আমরা এটা দুটি কারণে করলাম:
- Flows 액্টিভ থাকতে পারে এক্টিভিটি/ফ্র্যাগমেন্ট ব্যবহার না করলেও
- LiveData অনেক ডেভেলপারের কাছে পরিচিত, এবং আমি এই উদাহরণটিকে যতটুকু সম্ভব approachable বানাতে চেয়েছিলাম
এটি করতে পারতে, আপনাকে নিচের ডিপেন্ডেন্সি আপনার build.gradle ফাইলে যোগ করতে হবে:
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
আপনার এক্টিভিটি/ফ্র্যাগমেন্ট ক্লাসে, আপনি এই লাইভ ডেটা অবজার্ভ করতে পারেন এরকম:
myViewModel.todoItemFlow.observe(LocalLifecycleOwner.current) { todoItems -> // DataStore থেকে ডেটা এক্সেস করার লজিক }
DataStore কেন এবং কখন ব্যবহার করবেন
আমরা যা কিছু রিভিউ করলাম তার পর, এখন এলেphant in the room-র কথা বলার সময়। আপনি কি DataStore (Preferences অথবা Proto) আপনার বিদ্যমান বা পরবর্তী প্রজেক্টে ব্যবহার করবেন?
আমার মতামতে, উত্তর হ্যাঁ হওয়া উচিত। Google SharedPreferences থেকে দূরে যাচ্ছে সেটি বাশে, DataStore আপনাকে আপনার অ্যাপ্লিকেশনে ফোকাস করতে সাহায্য করার প্রচুর সুবিধা দেয় আপনার ডেটার পারসিস্টেন্সে না।
UI থ্রেড থেকে DataStore-র সাথে ইন্টারঅ্যাক্ট করা সেফ (যেহেতু এটি স্বয়ংক্রিয়ভাবে কাজটিকে I/O-তে সরিয়ে দেয়), এবং এটি আপনাকে Flow ব্যবহার করতে বাধ্য করে (আপনি যদি এখনও না করে থাকেন) এবং এর সব সুবিধা উপভোগ করতে। Preferences DataStore-এ SharedPreferences থেকে সহজে মাইগ্রেট করার একটি অপশনও রয়েছে।
আপনি যদি Room বনাম Proto DataStore ব্যবহার করার কথা চিন্তা করছেন, সেটি আপনার ইউজ কেসের ওপর নির্ভর করে। আপনি যে পরিমাণ ডেটা সংরক্ষণ করবেন (অথবা পারসিস্ট করবেন) সেটি যদি ছোট হয় এবং পারশিয়াল আপডেটের প্রয়োজন নয়, তবে Proto DataStore পথ। আপনার যদি বড় ডেটাসেট থাকে বা সেটি জটিল হতে পারে, তবে Room ব্যবহার করার জন্য.opt করুন।
আপনি যদি দেখতে চান এই সব কোডটি একটি অ্যাপ্লিকেশনে কীভাবে দেখায়, আপনি এখানে দেখতে পারেন:
আপনি যদি আমার লেখা অন্যান্য আর্টিকেল পড়তে চান, আপনি সেগুলো এখানে দেখতে পারেন:
পড়ার জন্য ধন্যবাদ!
রেফারেন্স:
- Protocol Buffers Documentation (proto 3)
- Working With Proto DataStore Codelab
- DataStore Documentation
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. Get started