এই নির্দেশিকায় UI স্টেট সম্পর্কে ব্যবহারকারীর প্রত্যাশা এবং স্টেট সংরক্ষণের জন্য উপলব্ধ বিকল্পগুলো নিয়ে আলোচনা করা হয়েছে।
সিস্টেম যখন হোস্ট অ্যাক্টিভিটি বা অ্যাপ্লিকেশন প্রসেসটি বন্ধ করে দেয়, তার পরে UI স্টেট দ্রুত সংরক্ষণ এবং পুনরুদ্ধার করা একটি ভালো ব্যবহারকারীর অভিজ্ঞতার জন্য অপরিহার্য। ব্যবহারকারীরা আশা করেন যে UI স্টেট একই থাকবে, কিন্তু সিস্টেম স্ক্রিনটি হোস্টকারী অ্যাক্টিভিটি এবং তার সংরক্ষিত স্টেটটি বন্ধ করে দিতে পারে।
ব্যবহারকারীর প্রত্যাশা এবং সিস্টেমের আচরণের মধ্যে ব্যবধান পূরণ করতে নিম্নলিখিত পদ্ধতিগুলোর সমন্বয় ব্যবহার করুন:
-
ViewModelঅবজেক্টসমূহ। - নিম্নলিখিত প্রেক্ষাপটগুলিতে সংরক্ষিত অবস্থা:
- Composables:
rememberSerializableএবংrememberSaveable। - ভিউমডেল:
SavedStateHandle।
- Composables:
- অ্যাপ ও স্ক্রিন পরিবর্তনের সময় UI অবস্থা ধরে রাখার জন্য স্থানীয় স্টোরেজ।
সর্বোত্তম সমাধানটি নির্ভর করে আপনার UI ডেটার জটিলতা, আপনার অ্যাপের ব্যবহারের ক্ষেত্র এবং ডেটা অ্যাক্সেসের গতি ও মেমরি ব্যবহারের মধ্যে ভারসাম্য খুঁজে বের করার উপর।
আপনার অ্যাপটি যেন ব্যবহারকারীদের প্রত্যাশা পূরণ করে এবং একটি দ্রুত ও প্রতিক্রিয়াশীল ইন্টারফেস প্রদান করে, তা নিশ্চিত করুন। UI-তে ডেটা লোড করার সময় বিলম্ব এড়িয়ে চলুন, বিশেষ করে রোটেশনের মতো সাধারণ কনফিগারেশন পরিবর্তনের পরে।
ব্যবহারকারীর প্রত্যাশা এবং সিস্টেমের আচরণ
ব্যবহারকারীর কার্যকলাপের উপর নির্ভর করে, তিনি আশা করেন যে UI-এর অবস্থা হয় মুছে যাবে অথবা অপরিবর্তিত থাকবে। কিছু ক্ষেত্রে সিস্টেম স্বয়ংক্রিয়ভাবে ব্যবহারকারীর প্রত্যাশা অনুযায়ী কাজ করে। অন্য ক্ষেত্রে সিস্টেম তার বিপরীত কাজ করে।
ব্যবহারকারী-প্রবর্তিত UI অবস্থা বরখাস্ত
ব্যবহারকারী আশা করেন যে, যখন তিনি কোনো স্ক্রিনে যান, তখন সেটির ক্ষণস্থায়ী UI অবস্থা ততক্ষণ পর্যন্ত একই থাকবে যতক্ষণ না তিনি সেটিকে সম্পূর্ণরূপে বন্ধ করে দেন। ব্যবহারকারী নিম্নলিখিত কাজগুলো করে একটি স্ক্রিন বা অ্যাপ সম্পূর্ণরূপে বন্ধ করতে পারেন:
- ওভারভিউ (সাম্প্রতিক) স্ক্রিন থেকে অ্যাপটি সোয়াইপ করে সরিয়ে দেওয়া।
- সেটিংস স্ক্রিন থেকে অ্যাপটি বন্ধ করা বা জোর করে বন্ধ করা।
- ডিভাইসটি রিবুট করা হচ্ছে।
- কোনো এক ধরনের "সমাপ্তি" ক্রিয়া সম্পন্ন করা (যা
Activity.finish()দ্বারা সমর্থিত)।
এই সম্পূর্ণ বাতিলের ক্ষেত্রে ব্যবহারকারীর ধারণা থাকে যে, তিনি স্ক্রিনটি থেকে স্থায়ীভাবে চলে গেছেন এবং ফিরে এলে স্ক্রিনটি একটি পরিষ্কার অবস্থা থেকে শুরু হবে। এই বাতিলের পরিস্থিতিগুলোর জন্য সিস্টেমের অন্তর্নিহিত আচরণ ব্যবহারকারীর প্রত্যাশার সাথে মিলে যায় — হোস্ট অ্যাক্টিভিটি ইনস্ট্যান্সটি ধ্বংস হয়ে যায় এবং মেমরি থেকে মুছে যায়, সাথে এর মধ্যে সংরক্ষিত যেকোনো স্টেট এবং এর সাথে যুক্ত যেকোনো সেভড স্টেট রেকর্ডও মুছে যায়।
সম্পূর্ণভাবে বাতিল করার এই নিয়মের কিছু ব্যতিক্রম আছে—উদাহরণস্বরূপ, একজন ব্যবহারকারী আশা করতে পারেন যে ব্যাক বাটন ব্যবহার করে ব্রাউজার থেকে বের হওয়ার আগে তিনি যে ওয়েবপেজটি দেখছিলেন, ব্রাউজারটি তাকে ঠিক সেখানেই নিয়ে যাবে।
সিস্টেম-প্রবর্তিত UI রাষ্ট্রীয় বরখাস্ত
একজন ব্যবহারকারী আশা করেন যে, স্ক্রিন ঘোরানো বা মাল্টি-উইন্ডো মোডে যাওয়ার মতো কোনো কনফিগারেশন পরিবর্তনের সময়ও এর UI স্টেট একই থাকবে। কিন্তু, ডিফল্টভাবে এই ধরনের কনফিগারেশন পরিবর্তন ঘটলে সিস্টেম হোস্ট অ্যাক্টিভিটিটি বন্ধ করে দেয় এবং এতে সংরক্ষিত সমস্ত UI স্টেট মুছে ফেলে। ডিভাইস কনফিগারেশন সম্পর্কে আরও জানতে, Jetpack Compose-এ কনফিগারেশন পরিবর্তনে প্রতিক্রিয়া (React to configuration changes) দেখুন।
উল্লেখ্য, কনফিগারেশন পরিবর্তনের ক্ষেত্রে ডিফল্ট আচরণকে অগ্রাহ্য করা সম্ভব (যদিও এটি সুপারিশ করা হয় না)। আরও বিস্তারিত জানতে ‘কনফিগারেশন পরিবর্তন পরিচালনা’ দেখুন।
একজন ব্যবহারকারী এটাও আশা করেন যে, যদি তিনি সাময়িকভাবে অন্য কোনো অ্যাপে চলে যান এবং পরে আপনার অ্যাপে ফিরে আসেন, তাহলেও আপনার অ্যাপের UI অবস্থা একই থাকবে। উদাহরণস্বরূপ, ব্যবহারকারী কোনো স্ক্রিনে কিছু সার্চ করার পর হোম বাটন চাপলেন বা একটি ফোন কল ধরলেন—যখন তিনি সার্চ স্ক্রিনে ফিরে আসবেন, তখন তিনি আশা করবেন যে সার্চের কীওয়ার্ড এবং ফলাফলগুলো ঠিক আগের মতোই সেখানে থাকবে।
এই পরিস্থিতিতে, আপনার অ্যাপটি ব্যাকগ্রাউন্ডে চলে যায় এবং সিস্টেম আপনার অ্যাপ প্রসেসটিকে মেমরিতে রাখার জন্য যথাসাধ্য চেষ্টা করে। তবে, ব্যবহারকারী যখন অন্য অ্যাপ ব্যবহার করতে ব্যস্ত থাকেন, তখন সিস্টেম অ্যাপ্লিকেশন প্রসেসটি বন্ধ করে দিতে পারে। এমন ক্ষেত্রে, হোস্ট অ্যাক্টিভিটিটি ধ্বংস হয়ে যায় এবং এর মধ্যে সংরক্ষিত সমস্ত স্টেটও নষ্ট হয়ে যায়। যখন ব্যবহারকারী অ্যাপটি পুনরায় চালু করেন, তখন স্ক্রিনটি অপ্রত্যাশিতভাবে একটি পরিষ্কার অবস্থায় থাকে। প্রসেস ডেথ সম্পর্কে আরও জানতে, প্রসেস এবং অ্যাপ লাইফসাইকেল দেখুন।
UI অবস্থা সংরক্ষণের বিকল্পগুলি
যখন UI অবস্থা সম্পর্কে ব্যবহারকারীর প্রত্যাশা সিস্টেমের ডিফল্ট আচরণের সাথে মেলে না, তখন আপনাকে অবশ্যই ব্যবহারকারীর UI অবস্থা সংরক্ষণ এবং পুনরুদ্ধার করতে হবে, যাতে সিস্টেম-প্রবর্তিত ধ্বংস প্রক্রিয়াটি ব্যবহারকারীর কাছে অদৃশ্য থাকে।
UI স্টেট সংরক্ষণের প্রতিটি বিকল্প নিম্নলিখিত দিকগুলোর উপর ভিত্তি করে ভিন্ন হয়, যা ব্যবহারকারীর অভিজ্ঞতার উপর প্রভাব ফেলে:
| ভিউমডেল | সংরক্ষিত অবস্থা | স্থায়ী সংরক্ষণ | |
|---|---|---|---|
| স্টোরেজ অবস্থান | স্মৃতিতে | স্মৃতিতে | ডিস্কে বা নেটওয়ার্কে |
| কনফিগারেশন পরিবর্তন সত্ত্বেও টিকে থাকে | হ্যাঁ | হ্যাঁ | হ্যাঁ |
| সিস্টেম-প্রবর্তিত প্রক্রিয়া মৃত্যু থেকে বেঁচে থাকে | না | হ্যাঁ | হ্যাঁ |
ব্যবহারকারী স্ক্রিন সম্পূর্ণভাবে বন্ধ করে দিলেও/ finish() | না | না | হ্যাঁ |
| ডেটার সীমাবদ্ধতা | জটিল অবজেক্টগুলো ঠিক আছে, কিন্তু উপলব্ধ মেমরির কারণে স্থান সীমিত। | শুধুমাত্র প্রিমিটিভ টাইপ এবং String মতো সরল, ছোট অবজেক্টের জন্য | শুধুমাত্র ডিস্কের স্থান অথবা নেটওয়ার্ক রিসোর্স থেকে তথ্য সংগ্রহের খরচ বা সময়ের দ্বারা সীমাবদ্ধ |
| পড়া/লেখার সময় | দ্রুত (শুধুমাত্র মেমরি অ্যাক্সেস) | ধীর (সিরিয়ালাইজেশন/ডিসেরিয়ালাইজেশন প্রয়োজন) | ধীর (ডিস্ক অ্যাক্সেস বা নেটওয়ার্ক ট্রানজ্যাকশন প্রয়োজন) |
কনফিগারেশন পরিবর্তনগুলি পরিচালনা করতে ViewModel ব্যবহার করুন
ব্যবহারকারী যখন সক্রিয়ভাবে অ্যাপ্লিকেশনটি ব্যবহার করছেন, তখন UI-সম্পর্কিত ডেটা সংরক্ষণ ও ব্যবস্থাপনার জন্য ViewModel একটি আদর্শ মাধ্যম। এটি UI ডেটাতে দ্রুত অ্যাক্সেস দেয় এবং উইন্ডো ঘোরানো, আকার পরিবর্তন এবং অন্যান্য সাধারণ কনফিগারেশন পরিবর্তনের সময় নেটওয়ার্ক বা ডিস্ক থেকে ডেটা পুনরায় আনার ঝামেলা এড়াতে সাহায্য করে। কীভাবে একটি ViewModel প্রয়োগ করতে হয় তা জানতে, ViewModel গাইডটি দেখুন।
ViewModel ডেটা মেমরিতে ধরে রাখে, যার মানে হলো ডিস্ক বা নেটওয়ার্ক থেকে ডেটা পুনরুদ্ধার করার চেয়ে এটি কম ব্যয়বহুল। একটি ViewModel একটি লাইফসাইকেল ওনারের সাথে যুক্ত থাকে, যেমন একটি নেভিগেশন ডেস্টিনেশন বা একটি অ্যাক্টিভিটি। কনফিগারেশন পরিবর্তনের সময় এটি মেমরিতে থেকে যায় এবং সিস্টেম স্বয়ংক্রিয়ভাবে ViewModel-টিকে সেই নতুন লাইফসাইকেল ওনার ইনস্ট্যান্সের সাথে যুক্ত করে, যা কনফিগারেশন পরিবর্তনের ফলে তৈরি হয়।
সেভড স্টেটের মতো নয়, সিস্টেম-প্রবর্তিত প্রসেস বন্ধ হয়ে গেলে ভিউমডেলগুলো ধ্বংস হয়ে যায়। সিস্টেম-প্রবর্তিত প্রসেস বন্ধ হওয়ার পর একটি ভিউমডেলের ডেটা পুনরায় লোড করতে, SavedStateHandle API ব্যবহার করুন। বিকল্পভাবে, যদি ডেটা UI-এর সাথে সম্পর্কিত হয় এবং ভিউমডেলে রাখার প্রয়োজন না হয়, তাহলে rememberSerializable ব্যবহার করুন। প্রিমিটিভ ডেটা টাইপের জন্য বা এমন পরিস্থিতিতে যেখানে আপনি @Serializable ব্যবহার করতে চান না, সেখানে rememberSaveable ব্যবহার করুন। যদি ডেটাটি অ্যাপ্লিকেশন ডেটা হয়, তবে এটিকে ডিস্কে সংরক্ষণ করা ভালো হতে পারে।
কনফিগারেশন পরিবর্তনের পরেও আপনার UI স্টেট সংরক্ষণের জন্য যদি আগে থেকেই কোনো ইন-মেমরি সমাধান থাকে, তাহলে আপনার ViewModel ব্যবহার করার প্রয়োজন নাও হতে পারে।
সিস্টেম-প্রবর্তিত প্রসেস বন্ধ হয়ে যাওয়া সামাল দেওয়ার জন্য ব্যাকআপ হিসেবে সংরক্ষিত অবস্থা ব্যবহার করুন।
Compose-এর rememberSerializable ও rememberSaveable এবং ViewModel-এর SavedStateHandle এর মতো API-গুলো সেইসব ডেটা সংরক্ষণ করে, যা সিস্টেম কোনো কম্পোনেন্ট ধ্বংস করে পরে আবার তৈরি করলে UI স্টেট পুনরায় লোড করার জন্য প্রয়োজন হয়। জটিল ডেটা স্ট্রাকচার আরও দক্ষতার সাথে পরিচালনা করার জন্য, SavedStateHandle তার saved {} এক্সটেনশনের মাধ্যমে Kotlinx Serialization সমর্থন করে, যা আপনাকে সাধারণ প্রিমিটিভ টাইপের পাশাপাশি টাইপ-সেফ অবজেক্টগুলোকেও নির্বিঘ্নে পারসিস্ট ও রিস্টোর করার সুযোগ দেয়। rememberSaveable ব্যবহার করে কীভাবে সেভড স্টেট প্রয়োগ করতে হয় তা জানতে, State and Jetpack Compose দেখুন।
সংরক্ষিত স্টেট বান্ডেলগুলো কনফিগারেশন পরিবর্তন এবং প্রসেস বন্ধ হয়ে যাওয়া, উভয় ক্ষেত্রেই টিকে থাকে, কিন্তু স্টোরেজ এবং গতির কারণে এগুলো সীমিত, কারণ বিভিন্ন এপিআই ডেটা সিরিয়ালাইজ করে। সিরিয়ালাইজ করা অবজেক্টগুলো জটিল হলে সিরিয়ালাইজেশন প্রচুর মেমরি খরচ করতে পারে। যেহেতু কনফিগারেশন পরিবর্তনের সময় এই প্রক্রিয়াটি মেইন থ্রেডে ঘটে, তাই দীর্ঘ সময় ধরে চলা সিরিয়ালাইজেশনের ফলে ফ্রেম ড্রপ এবং ভিজ্যুয়াল স্টাটার হতে পারে।
বিটম্যাপের মতো বিপুল পরিমাণ ডেটা, কিংবা দীর্ঘ সিরিয়ালাইজেশন বা ডিসিরিয়ালাইজেশনের প্রয়োজন হয় এমন জটিল ডেটা স্ট্রাকচার সংরক্ষণের জন্য সেভড স্টেট ব্যবহার করবেন না। এর পরিবর্তে, শুধুমাত্র প্রিমিটিভ টাইপ এবং String মতো সহজ ও ছোট অবজেক্ট সংরক্ষণ করুন। একইভাবে, অন্যান্য পার্সিস্টেন্স মেকানিজম ব্যর্থ হলে UI-কে তার পূর্বের অবস্থায় ফিরিয়ে আনার জন্য প্রয়োজনীয় ডেটা পুনরায় তৈরি করতে, একটি আইডির মতো ন্যূনতম পরিমাণ ডেটা সংরক্ষণের জন্য সেভড স্টেট ব্যবহার করুন। সিস্টেম-জনিত প্রসেস ডেথ সামাল দেওয়ার জন্য বেশিরভাগ অ্যাপেরই এটি প্রয়োগ করা উচিত।
আপনার অ্যাপের ব্যবহারের ধরনের ওপর নির্ভর করে, আপনার হয়তো সেভড স্টেট (saved state) ব্যবহার করার একেবারেই প্রয়োজন নাও হতে পারে। উদাহরণস্বরূপ, একটি ব্রাউজার ব্যবহারকারীকে ঠিক সেই ওয়েবপেজটিতে ফিরিয়ে নিয়ে যেতে পারে, যা তিনি ব্রাউজার থেকে বের হওয়ার আগে দেখছিলেন। যদি আপনার অ্যাক্টিভিটি এইভাবে কাজ করে, তবে আপনি সেভড স্টেট ব্যবহার না করে এর পরিবর্তে সবকিছু স্থানীয়ভাবে সংরক্ষণ করতে পারেন।
এছাড়াও, যখন আপনি একটি ইন্টেন্ট থেকে কোনো অ্যাক্টিভিটি খোলেন, তখন কনফিগারেশন পরিবর্তনের সময় এবং সিস্টেম অ্যাক্টিভিটিটি পুনরুদ্ধার করার সময়, উভয় ক্ষেত্রেই এক্সট্রা বান্ডেলটি অ্যাক্টিভিটিতে পৌঁছে দেওয়া হয়। অ্যাক্টিভিটিটি চালু করার সময় যদি কোনো UI স্টেট ডেটা, যেমন একটি সার্চ কোয়েরি, ইন্টেন্ট এক্সট্রা হিসেবে পাঠানো হতো, তাহলে আপনি সেভড স্টেট বান্ডেলের পরিবর্তে এক্সট্রা বান্ডেলটি ব্যবহার করতে পারতেন। ইন্টেন্ট এক্সট্রা সম্পর্কে আরও জানতে, ইন্টেন্ট এবং ইন্টেন্ট ফিল্টার দেখুন।
এই উভয় পরিস্থিতিতেই, কনফিগারেশন পরিবর্তনের সময় ডাটাবেস থেকে ডেটা পুনরায় লোড করে সময় নষ্ট করা এড়াতে আপনার একটি ViewModel ব্যবহার করা উচিত।
যেসব ক্ষেত্রে সংরক্ষণের জন্য UI ডেটা সহজ এবং হালকা হয়, সেখানে আপনি আপনার স্টেট ডেটা সংরক্ষণের জন্য শুধুমাত্র সেভড স্টেট API ব্যবহার করতে পারেন।
SavedStateRegistry ব্যবহার করে সংরক্ষিত অবস্থায় প্রবেশ করুন
Fragment 1.1.0 অথবা এর ট্রানজিটিভ ডিপেন্ডেন্সি Activity 1.0.0 থেকে শুরু করে, ComponentActivity মতো UI কম্পোনেন্টগুলো SavedStateRegistryOwner ইমপ্লিমেন্ট করে এবং একটি SavedStateRegistry প্রদান করে যা সেই কম্পোনেন্টের সাথে বাইন্ড করা থাকে। SavedStateRegistry কম্পোনেন্টগুলোকে আপনার সেভড স্টেটে হুক করার সুযোগ দেয়, যাতে তারা তা ব্যবহার করতে বা তাতে অবদান রাখতে পারে। উদাহরণস্বরূপ, ViewModel-এর জন্য সেভড স্টেট মডিউলটি একটি SavedStateHandle তৈরি করতে এবং আপনার ViewModel অবজেক্টগুলোতে তা সরবরাহ করতে SavedStateRegistry ব্যবহার করে। আপনি আপনার লাইফসাইকেল ওনারের ভেতর থেকে savedStateRegistry কল করে SavedStateRegistry টি পুনরুদ্ধার করতে পারেন।
যেসব কম্পোনেন্ট সংরক্ষিত স্টেটে অবদান রাখে, সেগুলোকে অবশ্যই SavedStateRegistry.SavedStateProvider ইমপ্লিমেন্ট করতে হবে, যা saveState() নামে একটিমাত্র মেথড সংজ্ঞায়িত করে। saveState() মেথডটি আপনার কম্পোনেন্টকে এমন একটি Bundle রিটার্ন করার সুযোগ দেয়, যাতে সেই কম্পোনেন্ট থেকে সংরক্ষণযোগ্য যেকোনো স্টেট অন্তর্ভুক্ত থাকে। SavedStateRegistry লাইফসাইকেল ওনারের লাইফসাইকেলের স্টেট সংরক্ষণ পর্যায়ে এই মেথডটিকে কল করে।
class SearchManager : SavedStateRegistry.SavedStateProvider {
companion object {
private const val QUERY = "query"
}
private val query: String? = null
...
override fun saveState(): Bundle {
return bundleOf(QUERY to query)
}
}
একটি SavedStateProvider রেজিস্টার করতে, SavedStateRegistry তে registerSavedStateProvider() কল করুন এবং প্রোভাইডারের ডেটার সাথে যুক্ত করার জন্য একটি কী (key) পাস করুন। প্রোভাইডারের ডেটার সাথে যুক্ত কী-টি পাস করে SavedStateRegistry তে consumeRestoredStateForKey() কল করার মাধ্যমে সেভড স্টেট থেকে প্রোভাইডারের পূর্বে সংরক্ষিত ডেটা পুনরুদ্ধার করা যায়।
একটি ComponentActivity মধ্যে, আপনি super.onCreate() কল করার পর onCreate() ) ফাংশনে একটি SavedStateProvider রেজিস্টার করতে পারেন। বিকল্পভাবে, আপনি একটি SavedStateRegistryOwner উপর একটি LifecycleObserver সেট করতে পারেন, যা LifecycleOwner ইমপ্লিমেন্ট করে, এবং ON_CREATE ইভেন্টটি ঘটলে SavedStateProvider টি রেজিস্টার করতে পারেন। একটি LifecycleObserver ব্যবহার করে, আপনি পূর্বে সংরক্ষিত স্টেটের রেজিস্ট্রেশন এবং পুনরুদ্ধারকে SavedStateRegistryOwner মূল অংশ থেকে পৃথক করতে পারেন।
class SearchManager(registryOwner: SavedStateRegistryOwner) : SavedStateRegistry.SavedStateProvider {
companion object {
private const val PROVIDER = "search_manager"
private const val QUERY = "query"
}
private val query: String? = null
init {
// Register a LifecycleObserver for when the Lifecycle hits ON_CREATE
registryOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_CREATE) {
val registry = registryOwner.savedStateRegistry
// Register this object for future calls to saveState()
registry.registerSavedStateProvider(PROVIDER, this)
// Get the previously saved state and restore it
val state = registry.consumeRestoredStateForKey(PROVIDER)
// Apply the previously saved state
query = state?.getString(QUERY)
}
}
}
override fun saveState(): Bundle {
return bundleOf(QUERY to query)
}
...
}
class SearchActivity : ComponentActivity() {
private var searchManager = SearchManager(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set up your Compose UI here
setContent {
// ...
}
}
}
জটিল বা বৃহৎ ডেটার ক্ষেত্রে প্রসেস ডেথ সামাল দিতে লোকাল পারসিস্টেন্স ব্যবহার করুন।
স্থায়ী লোকাল স্টোরেজ, যেমন একটি ডাটাবেস বা ডেটাস্টোর, ততক্ষণ পর্যন্ত টিকে থাকে যতক্ষণ আপনার অ্যাপ্লিকেশনটি ব্যবহারকারীর ডিভাইসে ইনস্টল করা থাকে (যদি না ব্যবহারকারী আপনার অ্যাপের ডেটা মুছে ফেলে)। যদিও এই ধরনের লোকাল স্টোরেজ সিস্টেম-চালিত অ্যাপ্লিকেশন প্রসেস বন্ধ হয়ে যাওয়ার পরেও টিকে থাকে, তবে এটি পুনরুদ্ধার করা ব্যয়বহুল হতে পারে, কারণ এটিকে লোকাল স্টোরেজ থেকে মেমরিতে পড়তে হয়। প্রায়শই এই স্থায়ী লোকাল স্টোরেজটি আপনার অ্যাপ্লিকেশন আর্কিটেকচারের একটি অংশ হতে পারে, যেখানে এমন সমস্ত ডেটা সংরক্ষণ করা হয় যা আপনি অ্যাপটি খোলা এবং বন্ধ করার সময় হারাতে চান না।
rememberSerializable , rememberSaveable , বা SavedStateHandle ব্যবহার করে সংরক্ষিত ViewModel বা স্টেট কোনোটিই দীর্ঘমেয়াদী স্টোরেজ সমাধান নয় এবং তাই এগুলো ডেটাবেসের মতো লোকাল স্টোরেজের বিকল্প নয়। এর পরিবর্তে, আপনার এই পদ্ধতিগুলো শুধুমাত্র ক্ষণস্থায়ী UI স্টেট সাময়িকভাবে সংরক্ষণের জন্য ব্যবহার করা উচিত এবং অ্যাপের অন্যান্য ডেটার জন্য পারসিস্টেন্ট স্টোরেজ ব্যবহার করা উচিত। আপনার অ্যাপ মডেল ডেটা দীর্ঘমেয়াদীভাবে (যেমন ডিভাইস রিস্টার্টের পরেও) ধরে রাখার জন্য কীভাবে লোকাল স্টোরেজ ব্যবহার করবেন সে সম্পর্কে আরও বিস্তারিত জানতে 'Guide to App Architecture' দেখুন।
UI স্টেট পরিচালনা: ভাগ করে জয় করা
বিভিন্ন ধরণের ডেটা সংরক্ষণ পদ্ধতির মধ্যে কাজ ভাগ করে দিয়ে আপনি দক্ষতার সাথে UI স্টেট সংরক্ষণ এবং পুনরুদ্ধার করতে পারেন। বেশিরভাগ ক্ষেত্রে, ডেটার জটিলতা, অ্যাক্সেসের গতি এবং জীবনকালের মতো বিষয়গুলোর ওপর ভিত্তি করে, এই পদ্ধতিগুলোর প্রত্যেকটিরই অ্যাপে ব্যবহৃত ভিন্ন ভিন্ন ধরণের ডেটা সংরক্ষণ করা উচিত।
- স্থানীয় স্থায়িত্ব: অ্যাপ্লিকেশনের সমস্ত ডেটা সংরক্ষণ করে, যা আপনি অ্যাপটি খোলা এবং বন্ধ করলেও হারাতে চান না।
- উদাহরণ: গানের অবজেক্টের একটি সংগ্রহ, যার মধ্যে অডিও ফাইল এবং মেটাডেটা অন্তর্ভুক্ত থাকতে পারে।
-
ViewModel: সংশ্লিষ্ট UI প্রদর্শনের জন্য প্রয়োজনীয় সমস্ত ডেটা এবং স্ক্রিন UI স্টেট মেমরিতে সংরক্ষণ করে।- উদাহরণ: সাম্প্রতিকতম অনুসন্ধানের গানের বস্তুগুলো এবং সাম্প্রতিকতম অনুসন্ধান কোয়েরি।
- সংরক্ষিত অবস্থা (
rememberSerializable,rememberSaveable, এবংSavedStateHandle): সিস্টেম বন্ধ হয়ে গেলে এবং তারপর UI পুনরায় তৈরি হলে, UI-এর অবস্থা পুনরায় লোড করার জন্য প্রয়োজনীয় অল্প পরিমাণ ডেটা এখানে সংরক্ষণ করে। এখানে জটিল অবজেক্ট সংরক্ষণ করার পরিবর্তে, জটিল অবজেক্টগুলোকে লোকাল স্টোরেজে সংরক্ষণ করুন এবং সংরক্ষিত অবস্থা API-গুলোতে এই অবজেক্টগুলোর জন্য একটি অনন্য আইডি সংরক্ষণ করুন।- উদাহরণ: সর্বশেষ অনুসন্ধানের ফলাফল সংরক্ষণ করা।
উদাহরণস্বরূপ, এমন একটি অ্যাপের কথা ভাবুন যা আপনাকে আপনার গানের লাইব্রেরিতে অনুসন্ধান করতে দেয়। বিভিন্ন ইভেন্ট যেভাবে পরিচালনা করা উচিত তা নিচে দেওয়া হলো:
যখন ব্যবহারকারী একটি গান যোগ করেন, তখন ViewModel তাৎক্ষণিকভাবে এই ডেটা স্থানীয়ভাবে সংরক্ষণ করার দায়িত্ব অর্পণ করে। যদি এই নতুন যোগ করা গানটি UI-তে দেখানো প্রয়োজন হয়, তবে গানটির সংযোজন প্রতিফলিত করার জন্য আপনার ViewModel অবজেক্টের ডেটাও আপডেট করা উচিত। মনে রাখবেন, ডেটাবেসে সমস্ত ডেটা সন্নিবেশের কাজ অবশ্যই মেইন থ্রেড থেকে করতে হবে।
যখন ব্যবহারকারী কোনো গান অনুসন্ধান করেন, তখন ডেটাবেস থেকে আপনি গানের যে জটিল ডেটাই লোড করুন না কেন, তা স্ক্রিনের UI স্টেটের অংশ হিসেবে অবিলম্বে ViewModel অবজেক্টে সংরক্ষিত হওয়া উচিত।
যখন অ্যাপটি ব্যাকগ্রাউন্ডে যায় এবং সিস্টেম স্টেট সংরক্ষণ করে, তখন সার্চ কোয়েরিটি সেভড স্টেট এপিআই (saved state APIs) ব্যবহার করে সংরক্ষণ করা উচিত, যাতে প্রসেসটি পুনরায় তৈরি হলে তা কাজে লাগে। যেহেতু এতে সংরক্ষিত অ্যাপ্লিকেশন ডেটা লোড করার জন্য এই তথ্যটি প্রয়োজন, তাই সার্চ কোয়েরিটি ViewModel-এর SavedStateHandle এ সংরক্ষণ করুন, অথবা আপনার কম্পোজেবলগুলোতে (composables) rememberSerializable বা rememberSaveable ব্যবহার করুন। ডেটা লোড করতে এবং UI-কে তার বর্তমান অবস্থায় ফিরিয়ে আনতে আপনার শুধু এইটুকুই তথ্য প্রয়োজন।
জটিল অবস্থা পুনরুদ্ধার: খণ্ডগুলো পুনরায় একত্রিত করা
যখন ব্যবহারকারীর অ্যাপে ফিরে আসার সময় হয়, তখন UI পুনরায় তৈরি করার জন্য দুটি সম্ভাব্য পরিস্থিতি রয়েছে:
- সিস্টেম অ্যাপ্লিকেশন প্রসেসটি শেষ করার পর UI পুনরায় তৈরি করা হয়। সিস্টেম সেভড স্টেট API ব্যবহার করে কোয়েরিটি সংরক্ষণ করে রাখে।
ViewModel(SavedStateHandleব্যবহার করে) অথবা কম্পোজেবল (rememberSerializableবাrememberSaveableব্যবহার করে) স্বয়ংক্রিয়ভাবে কোয়েরিটি পুনরুদ্ধার করে। যদি কম্পোজেবল কোয়েরিটি পুনরুদ্ধার করে, তবে এটি কোয়েরিটিViewModelকাছে পাঠিয়ে দেয়।ViewModelদেখে যে তার কাছে কোনো সার্চ রেজাল্ট ক্যাশ করা নেই এবং প্রদত্ত সার্চ কোয়েরি ব্যবহার করে সার্চ রেজাল্ট লোড করার দায়িত্ব অর্পণ করে। - কনফিগারেশন পরিবর্তনের পর UI পুনরায় তৈরি করা হয়। যেহেতু
ViewModelইনস্ট্যান্সটি নষ্ট হয়ে যায়নি, তাইViewModelমেমরিতে সমস্ত তথ্য ক্যাশ করা থাকে এবং এটিকে পুনরায় ডাটাবেস কোয়েরি করার প্রয়োজন হয় না।
অতিরিক্ত সম্পদ
UI স্টেট সংরক্ষণ সম্পর্কে আরও জানতে, নিম্নলিখিত রিসোর্সগুলো দেখুন।
কোডল্যাবস
বিষয়বস্তু দেখুন
{% হুবহু %}আপনার জন্য প্রস্তাবিত
- দ্রষ্টব্য: জাভাস্ক্রিপ্ট বন্ধ থাকলেও লিঙ্কের লেখা প্রদর্শিত হয়।
- ViewModel-এর জন্য সংরক্ষিত অবস্থা মডিউল
- লাইফসাইকেল-সচেতন কম্পোনেন্ট ব্যবহার করে লাইফসাইকেল পরিচালনা করা
- ভিউমডেলের সংক্ষিপ্ত বিবরণ