ذخیره سازی اطلاعات در برنامه های اندروید بوسیله کامپوننت Room بر پایه دیتابیس sqllite میباشد. این کامپوننت با استفاده از annotation هایی که برای کلاس ها تعریف میکنیم بصورت خودکار کلاس های ارتباط با دیتابیس را میسازد. برای کار با Room باید کلاس های خاصی ساخته شود که در زیر به انها میپردازیم قبل از هر چیز باید dependency به build . gradle بصورت زیر اضافه شود: استفاده از kapt به اندروید استودیو اجازه میدهد به کلاس های خودکار ساخته شده دسترسی داشته و بتوانیم از انها در برنامه استفاده کنیم. room - runtime شامل کتابخانه هایی برای ساختن کلاس های ارتباط با دیتابیس و room - compiler شامل کتابخانه هایی برای ساخت کلاس ها مورد نیاز از طریق annotation ها بصورت خودکار میباشد. حالا کافی است یکبار پروژه را sync کنید کلاس های مدل - Entity : هر یک از table های دیتابیس باید بصورت کلاس هایی با تعریف شود، بطور مثال: کلاس دیتابیس - Database : کلاس دیتابیس همانطور که از نامش پیداست معرف دیتابیس مورد استفاده میباشد. این کلاس نیز با تعریف میشود و دارای پارامتر هایی نیز میباشد، پارامتر های اولیه شامل کلاس های entity که تعریف شده و ورژن دیتابیس برای شناسایی تغییرات احتمالی بعدی دیتابیس میباشد. بطور مثال: کلاس های تبدیل داده - TypeConverter اغلب نوع اطلاعاتی که در دیتابیس ذخیره میشود با نوع مورد نیاز برنامه متفاوت است، مثلا در برنامه به نوع داده Date نیاز داریم ولی دیتابیس از ذخیره سازی این نوع پشتیبانی نمیکند، راه حل تبدیل نوع میباشد که میتوان به راحتی با متد های با تعریف شده و معرفی شده در Database اینکار را در Room انجام میدهیم، بطور مثال: و به این صورت در دیتابیس ان را اعلام میکنیم: رابط دسترسی به داده - DAO : برای اینکه بتوان با دیتابیس و table های ان ارتباط برقرار کرد، اینترفیسی با تعریف میکنیم که با استفاده از annotation یا دستورات صریح sqllite با دیتابیس تراکنش خواهد داشت: برای استفاده از dao یک متد abstract که مقدار برگشت ان از نوع dao است در Database میسازیم: کلاس مخزن - Repository گوگل توصیه میکند برای ارتباط با دیتابیس از الگوی Repository استفاده کنیم، این الگو دسترسی به دیتابیس را کپسوله کرده و به عنوان لایه بالاتر از دیتابیس میتوان برای گرفتن اطلاعات از وب سرویس یا منابع دیگر نیز استفاده کرد. برای مثال: همانطور که از کد بالا مشخص است Repository با الگوی singletone پیاده سازی شده، این الگو تضمین میکند فقط یک مخزن از داده در برنامه وجود داشته و هر بار که از طریق get ساخته میشود همان مخزن میباشد (چون constructor ان بصورت private تعریف شده نمیتوان نمونه جدیدی از روی ان ساخت) اما اینکار نیازمند ساخته شدن Repository در ابتدای اجرای برنامه توسط اندروید میباشد و اینکار باید در Application انجام شود، یعنی کلاسی میسازیم که از Application ارث بری کرده و ان را در متد oncreate مربوطه intialaize میکنیم: در ضمن باید حتما کلاس تعریف شده را در manifest نیز تعریف کنیم: حال کافی است در Repository دیتابیس را بسازیم و به ان دسترسی داشته باشیم: همانطور که میبینید برای ساخت دیتابیس به context و کلاس database و نام دیتابیس نیاز میباشد. حال به راحتی به dao دیتابیس دسترسی داشته و با ان ارتباط برقرار میکنیم. و کافی است در Viewmodel از Repository استفاده کنیم: حالا وقتی برنامه را اجرا کنیم با خطای زیر مواجه خواهیم شد: این خطا بدلیل اجرای کد Room در ترد اصلی برنامه است، جایی که UI در ان اجرا میشود و به صورت پیش فرض اندروید اجازه اجرای کارهای زمان بر را در این ترد نمیدهد. راه حل های مختلفی برای رفع این ایرور وجود دارد. یکی از آنها استفاده از LiveData است. LiveData یک نگهدارنده ( holder ) اطلاعات می باشد که به خوبی با Room هماهنگ می باشد و همچنین قابلیت انتقال اطلاعات بین ترد های مختلف را دارد. قبل از هر چیز باید dependency زیر اضافه شود: زمانی که از طریق DAO اطلاعات دیتابیس بصورت LiveData برگردانده میشود، اجرای برنامه روی ترد پس زمینه اجرا شده و پس از اتمام اجرا نتایج روی آن انتقال پیدا میکند. برای اینکار DAO را به شکل زیر تغییر میدهیم: و همچنین باید کد Repository را نیز به شکل زیر تغییر دهیم: و اما اصل ماجرا. LiveData از الگوی Observer استفاده میکند و باید برای استفاده از نتایج برگدانده توسط آن یک Observer برای آن تعریف کرد تا عملیاتی را که نیاز است بعد از تکمیل نتایج انجام شود در آن انجام داد. بطور معمول پس از دریافت نتایج نیاز به نمایش اطلاعات روی View برنامه می باشد، برای همین از متد onCreateView در fragment استفاده میکنیم، به صورت زیر: متد observe سه پارامتر دریافت میکند. پارامتر اول viewLifecycleOwner همان جزیی از برنامه است که چرخه حیات این LiveData به آن وابسته است ( fragment ) و در صورتی که چرخه حیات این بخش پایان یابد LiveData نیز به کار خود پایان خواهد داد و از بین خواهد رفت. چون اگر قبل از برگرداندن نتایج LiveData فرگمنت مورد نظر از بین برود و LiveData بخواهد اطلاعات را روی View نمایش دهد با ایرور مواجه شده و برنامه از کار می افتد، برای همین موضوع است که LiveData را یک lifecycle aware یعنی وابسته به چرخه حیات معرفی کرده اند. دومین پارامتر نیز متدی است که هنگام برگردانده شدن اطلاعات باید اجرا شود و بوسیله ان به راحتی میتوان view برنامه را آپدیت کرد. حال اگر برنامه را اجرا کنیم میبینیم که اطلاعات به راحتی از دیتابیس دریافت شده و در برنامه به نمایش در آمده است. نکات مهم: . دریافت اطلاعات از دیتابیس زمانبر بوده و ب باسته به حجم اطلاعات ممکن است از چند میلی ثانیه تا چند ثانیه طول بکشد. برای همین بسته به طراحی برنامه باید بر نحوه نمایش تغییر اطلاعات به کاربر پس از دریافت اطلاعات حتما پروسه ای تعیین گردد. مثلا استفاده از Loader یا دریافت اطلاعات از قبل در حافظه برنامه نمایش آن پس از دریافت کامل و از این دست کارها. یکی از روش هایی که برای جلوگیری از تغییر وضعیت برخی از المان های صفحه بصورت انیمیشنی اجرا میشود استفاده از ( View . jumpDrawablesToCurrentState است که جلو اجرای انیمیشن تغییر وضعیت مثلا CheckBox را پس از دریافت اطلاعات گرفته و مستقیما آن را نمایش میدهد: . اغلب ممکن است دریافت اطلاعات از دیتابیس نیازمند دریافت اطلاعات دیگر قبل از ان از دیتابیس باشد، مثلا ابتدا اطلاعات یک محصول با استفاده از id از دیتابیس گرفته میشود و سپس نیاز است مقدار فروش ان محصول از دیتابیس دریافت شود. در صورتی از LiveData استفاده شود هر دو نوع برگشت داده شده از دیتابیس از همین نوع است و دریافت نتیجه نیازمند دریافت اولین LiveData میباشد. برای اینکار میتوان از متد های transformation در LiveData استفاده کرد که دو نوع را بهم مرتبط میکند.