UI স্টেট সেভ করা

এই গাইড UI স্টেট সম্পর্কে ব্যবহারকারীর প্রত্যাশা এবং স্টেট সেভ করে রাখার জন্য উপলভ্য বিকল্পগুলি আলোচনা করে।

সিস্টেম হোস্ট অ্যাক্টিভিটি বা অ্যাপ্লিকেশন প্রসেস ধ্বংস করার পরে UI স্টেট দ্রুত সেভ ও রিস্টোর করা ভালো ব্যবহারকারীর অভিজ্ঞতার জন্য অপরিহার্য। ব্যবহারকারী আশা করেন যে UI স্টেট একই থাকবে, কিন্তু সিস্টেম স্ক্রিন হোস্ট করা অ্যাক্টিভিটি এবং এর সেভ করা স্টেট ধ্বংস করে দিতে পারে।

ব্যবহারকারীর প্রত্যাশা ও সিস্টেমের আচরণের মধ্যে পার্থক্য কমাতে, নিম্নলিখিত পদ্ধতিগুলির একটি করে ব্যবহার করুন:

  • ViewModel অবজেক্ট।
  • নিম্নলিখিত প্রসঙ্গে সেভ করা স্টেট:
  • অ্যাপ ও স্ক্রিন ট্রানজিশনের সময় UI স্টেট সেভ করে রাখার জন্য লোকাল স্টোরেজ।

সর্বোত্তম সমাধান আপনার UI ডেটার জটিলতা, আপনার অ্যাপের ব্যবহারের কেস এবং ডেটা অ্যাক্সেস স্পিড ও মেমরি ব্যবহারের মধ্যে ভারসাম্য খুঁজে পাওয়ার উপর নির্ভর করে।

নিশ্চিত করুন যে আপনার অ্যাপ ব্যবহারকারীদের প্রত্যাশা পূরণ করে এবং একটি দ্রুত, রেসপন্সিভ ইন্টারফেস অফার করে। UI-তে ডেটা লোড করার সময় দেরি এড়িয়ে চলুন, বিশেষ করে রোটেশনের মতো সাধারণ কনফিগারেশন পরিবর্তনের পরে।

ব্যবহারকারীর প্রত্যাশা ও সিস্টেমের আচরণ

ব্যবহারকারী যে অ্যাকশন নেন তার উপর নির্ভর করে, তারা UI স্টেট পরিষ্কার বা সংরক্ষিত হওয়ার প্রত্যাশা করেন। কিছু ক্ষেত্রে সিস্টেম ব্যবহারকারীর প্রত্যাশা অনুযায়ী অটোমেটিক কাজ করে। অন্যান্য ক্ষেত্রে সিস্টেমটি উল্টোটি করে।

ব্যবহারকারীর অনুরোধে UI স্টেট ডিসমিস করা

ব্যবহারকারী আশা করেন যে কোনও স্ক্রিনে নেভিগেট করলে, সেটি সম্পূর্ণভাবে ডিসমিস না করা পর্যন্ত এর ক্ষণস্থায়ী UI স্টেট একই থাকবে। ব্যবহারকারী নিম্নলিখিত কাজগুলি করে কোনও স্ক্রিন বা অ্যাপ সম্পূর্ণভাবে বাতিল করতে পারবেন:

  • ওভারভিউ (সাম্প্রতিক) স্ক্রিন থেকে অ্যাপটি সোয়াইপ করে সরিয়ে দেওয়া।
  • সেটিংস স্ক্রিন থেকে অ্যাপ বন্ধ করে দেওয়া বা জোর করে বন্ধ করা।
  • ডিভাইস রিবুট করা।
  • "সম্পূর্ণ করা" অ্যাকশন (যা Activity.finish() দ্বারা ব্যাক-আপ করা হয়) সম্পূর্ণ করা।

সম্পূর্ণভাবে বাতিল করার ক্ষেত্রে ব্যবহারকারী ধরে নেন যে তিনি স্থায়ীভাবে স্ক্রিন থেকে বেরিয়ে এসেছেন এবং ফিরে এলে, তিনি আশা করেন যে স্ক্রিনটি একটি ক্লিন স্টেট থেকে শুরু হবে। বাতিল করার এই ধরনের পরিস্থিতির জন্য অন্তর্নিহিত সিস্টেমের ব্যবহার ব্যবহারকারীর প্রত্যাশার সাথে মেলে - হোস্ট অ্যাক্টিভিটি ইনস্ট্যান্স ধ্বংস হয়ে যাবে এবং মেমরি থেকে সরানো হবে, এর সাথে এতে স্টোর করা যেকোনও স্টেট এবং এর সাথে যুক্ত যেকোনও সেভ করা স্টেট রেকর্ডও সরানো হবে।

সম্পূর্ণ বাতিল করা সংক্রান্ত এই নিয়মের কিছু ব্যতিক্রম আছে—যেমন, কোনও ব্যবহারকারী হয়ত আশা করতে পারেন যে ব্রাউজারটি তাকে ঠিক সেই ওয়েবপেজে নিয়ে যাবে যেটি তিনি ব্যাক বোতাম ব্যবহার করে ব্রাউজার থেকে বেরিয়ে আসার আগে দেখছিলেন।

সিস্টেম-ইনিশিয়েটেড UI স্টেট ডিসমিসাল

স্ক্রিন রোটেট করা বা মাল্টি-উইন্ডো মোডে পরিবর্তন করার মতো কনফিগারেশন পরিবর্তন চলাকালীন ব্যবহারকারী স্ক্রিনের UI স্টেট একই থাকবে বলে আশা করেন। তবে, ডিফল্ট হিসেবে, এই ধরনের কনফিগারেশন পরিবর্তন হলে সিস্টেম হোস্ট অ্যাক্টিভিটি ধ্বংস করে দেয়, এর ফলে এতে সেভ করা যেকোনও UI স্টেট মুছে যায়। ডিভাইস কনফিগারেশন সম্পর্কে আরও জানতে, Jetpack Compose-এ কনফিগারেশন পরিবর্তনের প্রতিক্রিয়া দেখুন।

মনে রাখবেন, কনফিগারেশন পরিবর্তনের জন্য ডিফল্ট আচরণ ওভাররাইড করা সম্ভব (যদিও এটি সাজেস্ট করা হয় না)। আরও বিবরণের জন্য কনফিগারেশন পরিবর্তন হ্যান্ডেল করা দেখুন।

এছাড়াও, কোনও ব্যবহারকারী যদি সাময়িকভাবে অন্য অ্যাপে যান এবং পরে আপনার অ্যাপে ফিরে আসেন, তাহলে তিনি আশা করেন যে আপনার অ্যাপের UI স্টেট একই থাকবে। যেমন, ব্যবহারকারী কোনও স্ক্রিনে সার্চ করেন এবং তারপরে হোম বোতাম প্রেস করেন বা কোনও ফোন কলের উত্তর দেন - সার্চ স্ক্রিনে ফিরে এলে তিনি আশা করেন যে সার্চ করা কীওয়ার্ড ও ফলাফল এখনও সেখানে থাকবে, ঠিক আগের মতো।

এই পরিস্থিতিতে, আপনার অ্যাপ ব্যাকগ্রাউন্ডে রাখা হয় এবং সিস্টেম আপনার অ্যাপ প্রসেস মেমরিতে রাখার জন্য সর্বাত্মক চেষ্টা করে। তবে, ব্যবহারকারী যখন অন্য অ্যাপের সাথে ইন্টার‍্যাক্ট করছেন, তখন সিস্টেম অ্যাপ্লিকেশন প্রসেস বন্ধ করে দিতে পারে। এই ধরনের ক্ষেত্রে, হোস্ট অ্যাক্টিভিটি ধ্বংস হয়ে যায় এবং এর মধ্যে সেভ করা যেকোনও স্টেটও ধ্বংস হয়ে যায়। ব্যবহারকারী অ্যাপ আবার চালু করলে, স্ক্রিন অপ্রত্যাশিতভাবে ক্লিন স্টেটে থাকে। প্রসেস ডেথ সম্পর্কে আরও জানতে, প্রসেস ও অ্যাপ লাইফসাইকেল দেখুন।

UI স্টেট বজায় রাখার বিকল্প

UI স্টেট সম্পর্কে ব্যবহারকারীর প্রত্যাশা ডিফল্ট সিস্টেম বিহেভিয়ারের সাথে না মিললে, সিস্টেম-ইনিশিয়েটেড ডেস্ট্রাকশন যাতে ব্যবহারকারীর কাছে ট্রান্সপারেন্ট হয় তা নিশ্চিত করতে আপনাকে অবশ্যই ব্যবহারকারীর UI স্টেট সেভ ও রিস্টোর করতে হবে।

UI স্টেট সেভ করার প্রতিটি বিকল্প নিম্নলিখিত বিষয়গুলির উপর নির্ভর করে আলাদা আলাদা হয় যা ব্যবহারকারীর অভিজ্ঞতাকে প্রভাবিত করে:

ViewModel সেভ করা স্টেট পার্সিস্ট্যান্ট স্টোরেজ
মেমরির জায়গা মেমরিতে মেমরিতে ডিস্ক বা নেটওয়ার্কে
কনফিগারেশন পরিবর্তন হলেও ডেটা থাকে হ্যাঁ হ্যাঁ হ্যাঁ
সিস্টেম-ইনিশিয়েটেড প্রসেস বন্ধ হয়ে গেলেও কাজ করে না হ্যাঁ হ্যাঁ
ব্যবহারকারী সম্পূর্ণ স্ক্রিন ডিসমিস/finish() করলেও এটি বন্ধ হয় না না না হ্যাঁ
ডেটা সংক্রান্ত সীমাবদ্ধতা জটিল অবজেক্ট ব্যবহার করা যায়, তবে উপলভ্য মেমরির কারণে স্পেস সীমিত থাকে শুধুমাত্র আদিম ধরনের এবং String-এর মতো সহজ, ছোট অবজেক্টের জন্য শুধুমাত্র ডিস্ক স্পেস বা নেটওয়ার্ক রিসোর্স থেকে ডেটা ফিরিয়ে আনার খরচ / সময় দ্বারা সীমিত
পড়া/লেখার সময় দ্রুত (শুধুমাত্র মেমরি অ্যাক্সেস) ধীর (সিরিয়ালাইজেশন/ডিসিয়ারিয়ালাইজেশন প্রয়োজন) ধীর (ডিস্ক অ্যাক্সেস বা নেটওয়ার্ক ট্রানজ্যাকশন প্রয়োজন)

কনফিগারেশন পরিবর্তন ম্যানেজ করতে ViewModel ব্যবহার করা

ব্যবহারকারী যখন অ্যাক্টিভভাবে অ্যাপ্লিকেশন ব্যবহার করছেন, তখন UI-সম্পর্কিত ডেটা স্টোর ও ম্যানেজ করার জন্য ViewModel আদর্শ। এটি UI ডেটা দ্রুত অ্যাক্সেস করতে দেয় এবং আপনাকে রোটেশন, উইন্ডো রিসাইজিং ও অন্যান্য সাধারণ কনফিগারেশন পরিবর্তন জুড়ে নেটওয়ার্ক বা ডিস্ক থেকে ডেটা রিফেচ করা এড়াতে সাহায্য করে। কীভাবে ViewModel প্রয়োগ করতে হয় তা জানতে, ViewModel গাইড দেখুন।

ViewModel মেমরিতে ডেটা ধরে রাখে, যার অর্থ হল ডিস্ক বা নেটওয়ার্ক থেকে ডেটা রিট্রিভ করার চেয়ে এটি রিট্রিভ করা অনেক সহজ। ViewModel একটি লাইফসাইকেল মালিকের সাথে যুক্ত থাকে, যেমন নেভিগেশন ডেস্টিনেশন বা অ্যাক্টিভিটি। কনফিগারেশন পরিবর্তন করার সময় এটি মেমরিতে থাকে এবং কনফিগারেশন পরিবর্তনের ফলে তৈরি হওয়া নতুন লাইফসাইকেল ওনার ইনস্ট্যান্সের সাথে সিস্টেম অটোমেটিক ViewModel-কে অ্যাসোসিয়েট করে।

সেভ করা স্টেটের মতো নয়, সিস্টেম-ইনিশিয়েটেড প্রসেস ডেথের সময় ViewModel ধ্বংস হয়ে যায়। ViewModel-এ সিস্টেম-ইনিশিয়েটেড প্রসেস ডেথের পরে ডেটা আবার লোড করতে, SavedStateHandle API ব্যবহার করুন। অথবা, ডেটা যদি UI-এর সাথে সম্পর্কিত হয় এবং ViewModel-এ রাখার প্রয়োজন না হয়, তাহলে rememberSerializable ব্যবহার করুন। প্রিমিটিভ ডেটা টাইপ বা এমন পরিস্থিতি যেখানে আপনি @Serializable ব্যবহার করতে চান না, সেখানে rememberSaveable ব্যবহার করুন। ডেটা অ্যাপ্লিকেশন ডেটা হলে, এটি ডিস্কে সেভ করে রাখলে ভাল হয়।

কনফিগারেশন পরিবর্তন জুড়ে আপনার UI স্টেট সেভ করার জন্য আপনার কাছে আগে থেকেই ইন-মেমরি সলিউশন থাকলে, আপনাকে ViewModel ব্যবহার করতে নাও হতে পারে।

সিস্টেম-ইনিশিয়েটেড প্রসেস বন্ধ করা ম্যানেজ করতে ব্যাক-আপ হিসেবে সেভ করা স্টেট ব্যবহার করা

সিস্টেম কোনও কম্পোনেন্ট ধ্বংস করে দিলে এবং পরে সেটি আবার তৈরি করলে, UI স্টেট আবার লোড করার জন্য প্রয়োজনীয় ডেটা Compose-এর rememberSerializable ও rememberSaveable এবং ViewModels-এর SavedStateHandle-এর মতো API সেভ করে। আরও দক্ষতার সাথে জটিল ডেটা স্ট্রাকচার ম্যানেজ করতে, saved {} এক্সটেনশনের মাধ্যমে SavedStateHandle Kotlinx সিরিয়ালাইজেশন কাজ করে, এর ফলে আপনি স্ট্যান্ডার্ড প্রিমিটিভ ধরনের পাশাপাশি টাইপ-সেফ অবজেক্ট নির্বিঘ্নে সেভ ও রিস্টোর করতে পারবেন। rememberSaveable ব্যবহার করে সেভ করা স্টেট কীভাবে ইমপ্লিমেন্ট করতে হয় তা জানতে, স্টেট ও Jetpack Compose দেখুন।

সেভ করা স্টেট বান্ডেল কনফিগারেশনে পরিবর্তন ও প্রসেস ডেথ, দু'টি ক্ষেত্রেই বজায় থাকে, তবে স্টোরেজ ও স্পিড দ্বারা সীমিত থাকে, কারণ বিভিন্ন API ডেটা সিরিয়ালাইজ করে। সিরিয়ালাইজ করা অবজেক্ট জটিল হলে, সিরিয়ালাইজেশনের জন্য অনেক মেমরি প্রয়োজন হতে পারে। কনফিগারেশন পরিবর্তনের সময় এই প্রসেসটি মূল থ্রেডে হওয়ার কারণে, অনেকক্ষণ ধরে চলা সিরিয়ালাইজেশনের ফলে ড্রপ করা ফ্রেম ও ভিজ্যুয়াল স্টাটার হতে পারে।

সেভ করা স্টেট ব্যবহার করে বিটম্যাপের মতো প্রচুর পরিমাণে ডেটা, অথবা জটিল ডেটা স্ট্রাকচার সেভ করবেন না, যার জন্য দীর্ঘক্ষণ ধরে সিরিয়ালাইজেশন বা ডিসিয়ারিয়ালাইজেশন করতে হয়। পরিবর্তে, শুধুমাত্র আদিম ধরন এবং সাধারণ, ছোট অবজেক্ট যেমন String স্টোর করুন। এই কারণে, সেভ করা স্টেট ব্যবহার করে ন্যূনতম পরিমাণ প্রয়োজনীয় ডেটা সেভ করুন, যেমন, UI আগের অবস্থায় ফিরিয়ে আনার জন্য প্রয়োজনীয় ডেটা আবার তৈরি করতে আইডি। অন্যান্য পারসিস্টেন্স মেকানিজম কাজ না করলে এটি করতে হবে। সিস্টেম-ইনিশিয়েটেড প্রসেস ডেথ ম্যানেজ করার জন্য বেশিরভাগ অ্যাপকে এটি প্রয়োগ করতে হবে।

আপনার অ্যাপের ব্যবহারিক ক্ষেত্রের উপর নির্ভর করে, আপনাকে সেভ করা স্টেট ব্যবহার করার প্রয়োজন নাও হতে পারে। যেমন, কোনও ব্রাউজার ব্যবহারকারীকে ঠিক সেই ওয়েবপেজে ফিরিয়ে নিয়ে যেতে পারে যেটি তিনি ব্রাউজার থেকে বেরিয়ে আসার আগে দেখছিলেন। আপনার অ্যাক্টিভিটি এইভাবে আচরণ করলে, আপনি সেভ করা স্টেট ব্যবহার করা বাদ দিতে পারেন এবং পরিবর্তে সবকিছু লোকালি পারসিস্ট করতে পারেন।

এছাড়াও, আপনি কোনও ইনটেন্ট থেকে অ্যাক্টিভিটি খুললে, কনফিগারেশন পরিবর্তন হলে এবং সিস্টেম অ্যাক্টিভিটি রিস্টোর করলে, দু'টি ক্ষেত্রেই অ্যাক্টিভিটিতে এক্সট্রা বান্ডেল ডেলিভার করা হয়। অ্যাক্টিভিটি লঞ্চ করার সময় যদি সার্চ কোয়েরির মতো কোনও UI স্টেট ডেটা ইনটেন্ট এক্সট্রা হিসেবে পাস করা হয়, তাহলে সেভ করা স্টেট বান্ডেলের পরিবর্তে আপনি এক্সট্রা বান্ডেল ব্যবহার করতে পারেন। ইনটেন্ট এক্সট্রা সম্পর্কে আরও জানতে, ইনটেন্ট ও ইনটেন্ট ফিল্টার দেখুন।

এইসব পরিস্থিতির যেকোনও একটিতে, কনফিগারেশন পরিবর্তনের সময় ডেটাবেস থেকে ডেটা আবার লোড করার জন্য সাইকেল নষ্ট করা এড়াতে আপনাকে এখনও একটি ViewModel ব্যবহার করতে হবে।

যেসব ক্ষেত্রে সংরক্ষিত UI ডেটা সহজ ও হালকা, সেখানে আপনার স্টেট ডেটা সেভ করতে আপনি শুধু সেভ করা স্টেট API ব্যবহার করতে পারেন।

SavedStateRegistry ব্যবহার করে সেভ করা স্টেটে হুক করা

Fragment 1.1.0 বা এর ট্রানজিটিভ ডিপেন্ডেন্সি Activity 1.0.0 থেকে শুরু করে, UI কম্পোনেন্ট, যেমন ComponentActivity, implement SavedStateRegistryOwner এবং একটি SavedStateRegistry প্রদান করে যা সেই কম্পোনেন্টের সাথে যুক্ত। SavedStateRegistry কম্পোনেন্টকে আপনার সেভ করা স্টেটে হুক করার অনুমতি দেয় যাতে সেটি ব্যবহার করা যায় বা সেটিতে কন্ট্রিবিউট করা যায়। যেমন, ViewModel-এর জন্য সেভ করা স্টেট মডিউল SavedStateRegistry ব্যবহার করে SavedStateHandle তৈরি করে এবং আপনার ViewModel অবজেক্টকে তা প্রদান করে। আপনি লাইফসাইকেল মালিকের কাছ থেকে 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() নম্বরে কল করুন, এর সাথে প্রদানকারীর ডেটা এবং প্রদানকারীকে অ্যাসোসিয়েট করার জন্য একটি কী দিন। প্রদানকারীর জন্য আগে সেভ করা ডেটা, consumeRestoredStateForKey() SavedStateRegistry-এ কল করে সেভ করা স্টেট থেকে রিট্রিভ করা যেতে পারে, এর জন্য প্রদানকারীর ডেটার সাথে যুক্ত কী পাস করতে হবে।

ComponentActivity-এর মধ্যে, super.onCreate()-এ কল করার পরে আপনি SavedStateProvider-এ onCreate() রেজিস্টার করতে পারবেন। অথবা, আপনি 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 {
            // ...
        }
    }
  }

জটিল বা বড় ডেটার জন্য প্রসেস ডেথ ম্যানেজ করতে লোকাল পারসিস্টেন্স ব্যবহার করা

ডেটাবেস বা DataStore-এর মতো স্থায়ী লোকাল স্টোরেজ ততক্ষণ পর্যন্ত থাকবে যতক্ষণ পর্যন্ত ব্যবহারকারীর ডিভাইসে আপনার অ্যাপ্লিকেশন ইনস্টল করা আছে (যদি না ব্যবহারকারী আপনার অ্যাপের ডেটা মুছে দেন)। সিস্টেম-ইনিশিয়েটেড অ্যাপ্লিকেশন প্রসেস ডেথ হলেও এই ধরনের লোকাল স্টোরেজ বেঁচে থাকে, তবে এটি রিট্রিভ করা কঠিন হতে পারে কারণ লোকাল স্টোরেজ থেকে মেমরিতে এটি পড়তে হবে। প্রায়ই এই স্থায়ী লোকাল স্টোরেজ আপনার অ্যাপ্লিকেশন আর্কিটেকচারের অংশ হতে পারে। আপনি অ্যাপ খুললে ও বন্ধ করলে যে ডেটা হারাতে চান না, তা স্টোর করার জন্য এটি ব্যবহার করা হয়।

rememberSerializable, rememberSaveable বা SavedStateHandle ব্যবহার করে সেভ করা ViewModel বা স্টেট কোনও দীর্ঘমেয়াদী স্টোরেজ সলিউশন নয় এবং তাই, ডেটাবেসের মতো লোকাল স্টোরেজের বিকল্প হিসেবে এগুলি ব্যবহার করা যায় না। পরিবর্তে, আপনাকে শুধুমাত্র ক্ষণস্থায়ী UI স্টেট সাময়িকভাবে স্টোর করার জন্য এইসব মেকানিজম ব্যবহার করতে হবে এবং অন্যান্য অ্যাপ ডেটার জন্য পারসিস্ট্যান্ট স্টোরেজ ব্যবহার করতে হবে। আপনার অ্যাপ মডেল ডেটা দীর্ঘমেয়াদী (যেমন, ডিভাইস রিস্টার্ট করা সত্ত্বেও) সেভ করে রাখার জন্য কীভাবে লোকাল স্টোরেজ ব্যবহার করবেন সেই সম্পর্কে আরও জানতে, অ্যাপ আর্কিটেকচার সংক্রান্ত গাইড দেখুন।

UI স্টেট ম্যানেজ করা: ভাগ করে সমাধান করা

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

  • লোকাল পারসিস্টেন্স: আপনি অ্যাপ খুললে ও বন্ধ করলে যেসব অ্যাপ্লিকেশন ডেটা মুছে দিতে চান না সেগুলি স্টোর করে।
    • উদাহরণ: গান অবজেক্টের সংগ্রহ, যার মধ্যে অডিও ফাইল ও মেটাডেটা থাকতে পারে।
  • ViewModel: সংশ্লিষ্ট UI, স্ক্রিন UI স্টেট দেখানোর জন্য প্রয়োজনীয় সব ডেটা মেমরিতে সেভ করে।
    • যেমন: সবচেয়ে সাম্প্রতিক সার্চের গান সংক্রান্ত অবজেক্ট এবং সবচেয়ে সাম্প্রতিক সার্চ কোয়েরি।
  • সেভ করা স্টেট (rememberSerializable, rememberSaveable এবং SavedStateHandle): সিস্টেম বন্ধ হয়ে গেলে এবং তারপর UI আবার তৈরি করলে, UI স্টেট আবার লোড করার জন্য প্রয়োজনীয় অল্প পরিমাণ ডেটা স্টোর করে। এখানে জটিল অবজেক্ট স্টোর করার পরিবর্তে, লোকাল স্টোরেজে জটিল অবজেক্ট পারসিস্ট করুন এবং সেভ করা স্টেট API-তে এইসব অবজেক্টের জন্য একটি অনন্য আইডি স্টোর করুন।
    • যেমন: সবচেয়ে সাম্প্রতিক সার্চ কোয়েরি সেভ করা।

যেমন, এমন একটি অ্যাপের কথা ভাবুন যা আপনাকে নিজের গান লাইব্রেরি সার্চ করতে দেয়। বিভিন্ন ইভেন্ট কীভাবে ম্যানেজ করতে হয় তা এখানে দেওয়া হল:

ব্যবহারকারী কোনও গান যোগ করলে, ViewModel অবিলম্বে এই ডেটা লোকালি সেভ করার দায়িত্ব অর্পণ করে। এই নতুন যোগ করা গানটি UI-তে দেখানো হলে, আপনাকে ViewModel অবজেক্টে ডেটা আপডেট করতে হবে যাতে গানটি যোগ করা হয়েছে তা বোঝা যায়। মনে রাখবেন, মূল থ্রেড থেকে সব ডেটাবেস ইনসার্ট করতে হবে।

ব্যবহারকারী কোনও গান সার্চ করলে, আপনি ডেটাবেস থেকে যত জটিল গানের ডেটা লোড করুন না কেন, সেটি স্ক্রিন UI স্টেটের অংশ হিসেবে ViewModel অবজেক্টে সঙ্গে সঙ্গে সেভ করতে হবে।

অ্যাপ ব্যাকগ্রাউন্ডে চলে গেলে এবং সিস্টেম স্টেট সেভ করলে, প্রসেস আবার তৈরি করার প্রয়োজন হলে সেভ করা স্টেট API ব্যবহার করে সার্চ কোয়েরি সেভ করতে হবে। যেহেতু এই তথ্যটি অ্যাপ্লিকেশন ডেটা লোড করার জন্য প্রয়োজনীয়, তাই ViewModel-এ সার্চ কোয়েরি সেভ করুন SavedStateHandle অথবা আপনার কম্পোজেবল কোডে rememberSerializable বা rememberSaveable ব্যবহার করুন। ডেটা লোড করতে এবং UI-কে তার বর্তমান অবস্থায় ফিরিয়ে আনতে আপনার এই তথ্যগুলিই প্রয়োজন।

জটিল স্টেট ফিরিয়ে আনা: টুকরোগুলি আবার একত্রিত করা

ব্যবহারকারী যখন অ্যাপে ফিরে আসেন, তখন UI রিক্রিয়েট করার জন্য দুটি সম্ভাব্য দৃশ্যকল্প থাকে:

  • সিস্টেম অ্যাপ্লিকেশন প্রসেস শেষ করার পরে UI আবার তৈরি করা হয়। সিস্টেমের কাছে সেভ করা স্টেট API ব্যবহার করে সেভ করা কোয়েরি আছে। ViewModel (ব্যবহার করে SavedStateHandle) বা কম্পোজ করার উপযুক্ত (rememberSerializable বা rememberSaveable ব্যবহার করে) অটোমেটিক কোয়েরি রিস্টোর করে। কম্পোজ করা যায় এমন কোয়েরি রিস্টোর করলে, এটি ViewModel-এ কোয়েরিটি পাস করে। ViewModel দেখে যে এর কাছে কোনও ক্যাশে করা সার্চ ফলাফল নেই এবং প্রদত্ত সার্চ কোয়েরি ব্যবহার করে সার্চ ফলাফল লোড করার দায়িত্ব অন্য কাউকে দেয়।
  • কনফিগারেশনে পরিবর্তন করার পরে UI আবার তৈরি করা হয়। ViewModel ইনস্ট্যান্সটি ধ্বংস করা হয়নি বলে, ViewModel-এর কাছে মেমরিতে ক্যাশে করা সমস্ত তথ্য রয়েছে এবং এটি ডেটাবেসকে আবার কোয়েরি করার প্রয়োজন নেই।

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

UI স্টেট সেভ করা সম্পর্কে আরও জানতে, নিম্নলিখিত রিসোর্স দেখুন।

কোডল্যাবস

কন্টেন্ট দেখা