اگر برنامه نویسی اندروید بدون معماری انجام شود، نگهداری و روزآمدسازی کدها دستی و سخت میشود. در این بسته به آموزش معماری پیشنهادی گوگل در برنامه نویسی اندروید میپردازیم. بسته آموزش معماری MVVM در اندروید در واقع فصل پنجم از بسته جامع آموزش برنامه نویسی اندروید با کاتلین و استاندارد گوگل (+) است. البته این بسته به صورت مستقل نیز قابل استفاده است.
پس از این فصل موارد زیر توصیه میشود:
- دیتابیس Room در اندروید با رعایت معماری MVVM (+)
- رتروفیت (کار با سرور) و ریسایکلرویو در اندروید با معماری MVVM (+)
معماری نرم افزار چیست ؟
معماری یا Architecture در برنامهنویسی یعنی نحوه جداسازی و تقسیم وظیفه میان کلاسهای یک برنامه. نوع نگاه در جداسازی کلاسها انواع معماریها را پذید میآورد.
معماریهایی چون MVC (سرنام Model View Controller) یا MVP (مخفف Model View Presenter) از انواع معماریهای رایج هستند.
معماری MVVM چیست ؟
معماری MVVM یا Model View View-Model یک سبک معماری سه بخشی است. در این سبک بخش Model وظیفه مدلسازی انواع داده را بر عهده دارد. بخش View دربردارنده اجزای رابط کاربری است. بخش View-Model دادههای لازم برای نمایش در رابط را از مخزن (دیتابیس یا شبکه) میگیرد و پردازش میکند.
برنامه نویسی اندروید با معماری MVVM ؟
در آغاز راه تا حوالی سالهای 2016 برنامهنویسی اندروید بسیار شلخته بود. اکتیویتیها یا فرگمنتها چندین کار را بر عهده داشتند. رویدادها را مدیریت میکردند. دادهها را برای نمایش پردازش میکردند. با دیتابیس ارتباط داشتند. و بسیاری موارد دیگر. به این ترتیب کلاس اکتیویتی معمولا بسیار شلوغ و نگهداری آن دشوار بود.
البته از سالهای آغازین دهه 2010 برنامهنویسان روی این موضوع بحث داشتند. برای مثال این مقاله (+) را در سال 2010 ببینید.
با معرفی پروژه Jetpack و کتابخانه AndroidX (که در فصلهای قبل هم با آن کار کردیم) موضوع تغییر کرد. گوگل کم کم ابزارها و کتابخانههایی را برای کدنویسی ساختارمند اندروید تدارک دید. امکان DataBinding و کتابخانه Navigatio و LifeCycle از این جملهاند. که در فصلهای 2 تا 4 از این مجموعه با این سه آشنا شدیم.
معماری استاندارد گوگل نوعی معماری MVVM با کمی تغییر است. در عمل پذیرفته شده است که معماری استاندارد اندروید امروزه معماری MVVM است.
این دوره در یک نگاه
این آموزش با تحویل یک اپلیکیشن جذاب «حدس واژه» یا «ادا بازی» اما فاقد معماری آغاز میشود. شما اصول توسعه اپلیکیشن را در چهار فصل گذشته آموختهاید. پس در اینجا زمان را برای توسعه از صفر صرف نمیکنیم. با یک اپلیکیشن آماده شروع میکنیم.
در طول این آموزش رفته رفته معماری MVVM را به ساختار کدهای این اپلیکیشن تزریق میکنیم.
ابتدا با مفهوم View-Model و کاربرد آن آشنا میشویم. سپس کدهای مرتبط با View-Model را از واحد UI Controller جدا میکنیم.
سپس با مفهوم LiveData آشنا میشویم. برای اتصال غیرمستقیم میان VM و UC از این کلاس استفاده میکنیم.
نکات ریز و مهمی در استفاده از LiveData وجود دارد. همگی گفته میشود. تفاوت MutableLiveData و LiveData از آن جمله است. همچنین است تبدیل و نگاشت LiveData با استفاده از تابع Map.
در پایان این دوره اپلیکیشن ما کاملا با ساختار معماری MVVM سازگار شده است. مهمتر این که شما میتوانید اپ های تازهای با اساس MVVM بنویسید.
آموزههای اصلی
- آموزش برنامه نویسی اندروید با کاتلین
- مفهوم معماری یا Architucture
- مفهوم معماری MVVM یا Model View View-Model
- مفهوم View-Model و کاربرد آن
- مفهوم UI Controller و کاربرد آن
- مفهوم LiveData و کاربرد آن
- مفهوم ModelViewProvider
- مدلسازی Event با LiveData
- تفاوت MutableLiveData و LiveData
- کار با زمان سنج یا Timer در اندروید
- کار با DateUtil برای فرمت کردن زمان
- تابع با پارامتر Generic در کاتلین
- ترکیب DataBinding و ViewModel
- ترکیب DataBinding و LiveData
- استفاده از الگوی Factory و ایجاد ViewModel با داده اولیه
- آشنایی با Transformation.Map برای نگاشت LiveData
این آموزش معماری mvvm در اندروید بینظیر است زیرا
- بر اساس استاندارد روز گوگل تهیه شده است.
- برنامه نویسی اندروید با کاتلین آموزش داده شده است.
- میآموزید که چطور توسعه اندروید را معماری کنید.
- برنامهنویسی اندروید با معماری مورد پذیرش گوگل را میآموزید.
- هم مفهومی و هم عملی میآموزید که معماری MVVM چیست ؟
پیشنیاز
فصلهای 1 تا 4 از این مجموعه
کلیدواژگان
آموزش برنامه نویسی اندروید با کاتلین . آموزش معماری mvvm در اندروید برنامه نویسی اندروید با معماری MVVM . معماری MVVM چیست ؟ معماری نرم افزار چیست ؟ معماری اندروید . مفهوم LiveData . مفهوم View-Model . مقایسه MVC و MVVM . مقایسه MVP و MVVM .
محمدمتین محمدی –
سلام مهندس جان ، ضمن سپاس از اموزش های خوبتون یه درخواست دارم. درخواستم اینه که خواهشا فصل api هم ضبظ کنید بی صبرانه منتظر هستیم.ممنون
مصطفی آصفی –
سلام مجدد به شما آقای محمدی. در این نشانی، آموزش رتروفیت برای کار با API (+) منتشر شده که میتونید استفاده کنید.
احمد –
سلام ببخشید من یک سوال داشتم من دوره شما را تماشا کردم ولی سوالی که دارم این است که اگر ما بخواهیم یک toast و یا alert dialog با متنی که براساس یک شرایطی تغییر میکنه این متن باید از view model بیاد. ولی اگر متن ثابت بود چی؟ میتونیم در ui controller یک متن ثابت را در toast یا موارد دیگر پاس داد؟ مثلا کد زیر تو ui controller باشد مشکل ندارد؟
Toast.makeText(this, “text”, Toast.LONG_LENGTH).show()
محمد کاظمیان (خریدار محصول) –
من با کمک آموزش خوبتون بخشی از پروژه ام رو با ساختار mvvm منطبق دادم که خب کدها خیلی تمیز و خوب شدند اما مشکلی که باهاش مواجه هستم این هستش که من از BottomNavigation استفاده می کنم زمانی که هر کدوم از فرگمنت های این BottomNavigation رو اجرا می کنم میبینم فرگمنت reCreate میشه و state خودش رو حفظ نمی کنه. متد init viewModel هم دوباره صدا زده میشه. برای اینکه state فرگمنت باقی بمونه در جایی که ویومدل رو به فرگمنت معرفی می کنم به ViewModelProvider به جای this مقدار requireActivity پاس دادم فرگمنت دیگه reCreate نشد اما ظاهرا استفاده از requireActivity خیلی هزینه بر هست و لود فرگمنت رو خیلی خیلی با کندی مواجه کرده در حدی که آیتم های ریسایکلرویو به سختی اسکرول میشن
مهندس آصفی عزیز شما راه حلی برای حفظ وضعیت فرگمنت ها دارین؟
مصطفی آصفی –
سلام به شما. خب خیلی خوبه که کدهاتون تمیز و قابل نگهداری شده. خوشحالم که کم کم استفاده از معماری در برنامه نویسی همه گیر میشه.
در مورد مدیریت وضعیت فرگمنت ها توصیه می کنم اول آموزش چرخه حیات در اندروید و حتی آموزش نویگیشن در اندروید که فصل های قبلی هستند رو ببینید تا اصولی بتونید بحث مدیریت فرگمنت ها رو انجام بدید. اونجا در مورد حالت های فرگمنت ها صبحت کردم. بعد از دیدن اون ها می تونیم با یک ادبیات مشترک تبادل نظر کنیم.
آریا ماهاور (خریدار محصول) –
سلام جناب آصفی
ممنون از آموزش خوبتون ، به نظرم نحوه تدریستون عمیق هستش و مفاهیم پیچیده رو خیلی خوب منتقل میکنید و توی منابع فارسی یک سر و گردن این آموزش بالاتر از بقیه بود ، میخواستم بدونم امکانش هست آموزش hilt و ktor رو هم بزارید مخصوصا مبحث hilt , dagger به نظرم خیلی حیاتی هستش برای برنامه نویسی اندروید . با تشکر
مصطفی آصفی –
سلام به شما آقای ماهاور. در رابطه با خواسته شما، دو آموزش پایین هم به همین سبک ادامه پیدا کرد و منتشر شد:
آموزش رتروفیت در اندروید برای کار با API و معماری MMV (+)
آموزش ساخت نمای سفارشی در اندروید و معماری MVVM (+)
پینوشت: ممنون از لطف شما و این که برای ابراز محبتتون وقت گذاشتید. هدف اصلی در همرویش هم همین هست که آموزشها ژرف باشن و به جز معرفی یک ابزار یا پلتفرم بتونن یک درک خوبی ایجاد کنن که برنامه نویس بتونه بین ابزارها به راحتی حرکت کنه.
محمد کاظمیان (خریدار محصول) –
ممنونم ازتون بابت این آموزش فوق العاده
مفهوم viewModel رو خیلی عالی توضیح دادین
جسارتا استاد برنامه ای برای آموزش ارتباط با سرور ، Paging و استفاده از viewModel در ریسایکلرویو دارین ؟
مصطفی آصفی –
سلام به شما آقای کاظمیان. در رابطه با خواسته شما، دو آموزش پایین هم به همین سبک ادامه پیدا کرد و منتشر شد:
آموزش رتروفیت در اندروید برای کار با API و معماری MVVM
(+) آموزش ساخت نمای سفارشی در اندروید و معماری MVVM (+)
پینوشت: ممنون از لطف شما و این که برای ابراز محبتتون وقت گذاشتید.
امیرمحمد (خریدار محصول) –
استاد اموزش استفاده از volley در معماری mvvm نمیزارید؟
اگر نمیزارید لطفا یک رفرنس معرفی میکنید
مصطفی آصفی –
سلام به شما. دو آموزش پایین هم به همین سبک ادامه پیدا کرد و منتشر شد:
آموزش رتروفیت در اندروید برای کار با API و معماری MVVM(+)
آموزش ساخت نمای سفارشی در اندروید و معماری MVVM (+)
امیرمحمد (خریدار محصول) –
حل شد یادم رفته بود implemet کنم
مصطفی آصفی –
سلام و ممنون که مجددا اون شب اطلاع دادید. انشالله که موفق باشید.
امیرمحمد (خریدار محصول) –
استاد در پروژه جدید من ViewModelProvider همچین اروری میده ممنون میشم کمک کنید
(در ضمن ViewModel هم هیچ پارامتر ورودی نداره که نیاز به ViewModelFactory باشه) :
None of the following functions can be called with the arguments supplied
امیرمحمد (خریدار محصول) –
استاد من میخوام خودم از نو پروژه درست کنم که از دیتا باندینگ استفاده کنم اما بایندینگ فرگمنت هام ساخته نمیشه
مثلا همین برنامه حدس کلمه رو میخوام درست کنم از نو TitleFragmentBinding اصلا نیست ممنون میشم راهنمایی کنید
مصطفی آصفی –
سلام به شما. ببینید اگه مراحل رو در مورد پروژه دوره پیش بردین و مشکلی نبود و حالا یک پروژه مشابه همون دقیقتا با همون کدها گام به گام می سازید و مشکل هست احتمالا به دلیل نارسایی کتابخونه بایندینگ در اندرویده که گاهی این رو داره. گاهی با re-build و پاک کردن حافظه گریدل و از نو بیلد کردن پروژه حل میشه. گاهی هم می بینید پیدا نمی کنه ولی دستی می نویسید و اجرا میشه بدون مشکل.
امیرمحمد (خریدار محصول) –
DSL element ‘android.dataBinding.enabled’ is obsolete and has been replaced with ‘android.buildFeatures.dataBinding’.
It will be removed in version 5.0 of the Android Gradle plugin.
Affected Modules: app
این رو چطوری میشه رفعش کرد؟
مصطفی آصفی –
سلام به شما. این خطا داره می گه که شیوه فعال کردن دیتابایندیگ در نسخه جدید گریدل گوگل عوض شده.
از این نسخه گریدل (Android Gradle Plugin 4.0.0-alpha05) به بعد برای فعال کردن دیتابایندیگ در فایل build.gradle ماژول app خودتون این خط رو باید اضافه کنید:
android.buildFeatures.dataBinding true
امیرمحمد (خریدار محصول) –
استاد دلیل استفاده از viewmodelFactory رو متوجه نمیشم لطفا یک توضیح مختصری میفرمایید
مصطفی آصفی –
سلام به شما. ببینید ما برای ایجاد ViewModel از ViewModelProvider استفاده می کنیم. این روش خوبیه ولی همون طور که در آموزش هم عرض کردم، زمانی که شما بخواهید ViewModel رو بهش یک پارامتری پاس بدین و بعد ازش نمونه بسازید ViewModelProvider نمی تونه پارامتر بپذیره. پس میاید یک Factory تعریف می کنید که اول ViewModel با استفاده از پارامترهای اولیه ساخته بشه و بعد این Factory آماده شده رو به ViewModelProvider پاس میدید تا نمونه مورد نظر از ViewModel ترکیبی رو بتونه ایجاد کنه.
پینوشت – شاید با خودتون فکر بکنید که این چه کاریه. خب همین قابلیت رو در دل ViewModel می گذاشتیم. ولی موضوع اینه که در مهندسی نرم افزار همیشه الگوها به این دلیل ایجاد میشن که کارها رو تفکیک کنن. وقتی حرفه ای تر بشین و در برنامه ها مدام با روزآمدسازی اجزای مختلف سروکار پیدا کنید متوجه توجیه این سخت کردن کار خواهید شد: این که آدم بتونه یک بخشی (مثلا یک Factory رو) به روز کنه بدون دخالت در کدهای ViewModel. چیزی شبیه توجیه جدا کردن فرانت اند و یک اند .
مرتضی –
سلام
خسته نباشید
سوالی درباره recyclerview که داخل معماری adapter کجا قرار میگیره viewModel ? دسترسی به ایتم ها از طریق databinding چطوری میشه
ممنونم از دوره خوبی که ارایه کردید
مصطفی آصفی –
سلام به شما آقای قربانی. در رابطه با خواسته شما، آموزش پایین منتشر شده که هم به بحث اتصال به اینترنت در اندروید و هم ساخت ریسایکلرویو پرداخته شده:
آموزش رتروفیت در اندروید برای کار با API و معماری MVVM (+)
امین دهقان (خریدار محصول) –
سلام مجدد خطی که اشاره فرمودید رو **** دیتابیس در اندروید (+)**** رو در آموزش Room دیدم
این خط هست
{(android:onClick=”@{() -> sleepQualityViewModel.onSetSleepQuality(4)}”
اما همانطور که ملاحظه میکنید و قبلا هم عرض کردم در اینجا مقدار 4 به صورت استاتیک وجود دارد
و سوال بنده از اول این بود که اگر بخواهم به جای مقدار 4 تکسک یک edit terxt رو چگونه ارسال کنم ؟
{(android:onClick=”@{() -> sleepQualityViewModel.onSetSleepQuality(myEditTextName.Text)}”
و این کار را میخاهم از طریق xml انجام بدهم
خیلی ممنون میشم اگر کمک کنید
مصطفی آصفی –
سلام به شما. ببینید همون طور که خدمتتون عرض کردم شما می تونید به تابع خاصی هم بایند کنید
android:text=”@={viewmodel.yourFunction}”
و این تابع می تونه تابع یا Watcher مربوط به EditText شما باشه که خروجی اون نهایتا برگرده به TextView مورد نظر.
امین دهقان (خریدار محصول) –
خیلی ممنون مشکلم حل شد فقط تو این خط که نوشتین
(android:onClick=”@{() -> sleepQualityViewModel.onSetSleepQuality(1)}”
اگر به جای 1 بخام مقدار editText را بدم چطور میشه
مثلا
(android:onClick=”@{() -> sleepQualityViewModel.onSetSleepQuality(editText.Text)}”
خیلی ممنون
امین دهقان (خریدار محصول) –
بله من میخام مقدار را از xml بایند کنم داخل یه ویو مدل
اما تابع من ورودی دارد یعنی باید اینطوری استفاده بشه (????)ViewModel.myFunction و مقدار ورودی این فانکشن تکسته editText هست
پاسخی که شما فرمودین
viewmodel.yourFunction برای فانکشن بدون ورودی هست
مصطفی آصفی –
سلام دوباره. اگه تابع شما مثلا یک ورودی int دریافت می کنه (برای مثال) می تونید داخل همون پرانتز تابع در xml پاس بدین این ورودی رو.
مثلا خط کد زیر مربوط به فصل دیتابیس در اندروید (+) هست که در اون در پاسخ رویداد onClick اومدیم و با کلیک روی هر شکل یک عدد مثلا در زیر عدد 1 رو پاس دادیم:
android:onClick=”@{() -> sleepQualityViewModel.onSetSleepQuality(1)}”
امین دهقان (خریدار محصول) –
سلام ممنونم از پاسخ به سوال قبلیم
ی سوال دیگه داشتم
شما تو آموزش از edit Text استفاده نفرمودین فقط textView هارو به ViewModel ارتباط دادین
حالا فرض بگیریم من تو ViewModel ام یه تابع دارم که ورودی داشته باش و ورودی رو هم از editText باید بخونه
مثل این
fun SetTest(txt :String){
_ResultMsg.value= txt
}
حالا چطور می تونم داخل xml مقدار editText رو به تابع داخل ViewModel ام (?)ViewModel.setText بایند کنم
جسارتا اگر تو ویدیو های آموزشی هست بفرمایید
مصطفی آصفی –
سلام به شما. اگه هدف شما بایند کردن text ویجت EditText از داخل xml هست می تونید به صورت پایین عمل کنید.
android:text=”@={viewmodel.yourFunction}”
امین دهقان (خریدار محصول) –
روز به خیر مهندس
به خطای سطح پایینی برخورد کردم که متاسفانه وقت زیادی ازم گرفته
ابتدا
رو به xml اضافه میکنم و در فرگمنت از این طریق
binding.scregViewModel=viewModel
ویو مدل رو به xml متصل میکنم
اما هنگام build این خطا برام ایجاد میشه
Type mismatch: inferred type is com.behstanpakhsh.behapp.Ui.Stock.Sc.ScRegViewModel but Ui.Stock.Sc.ScRegViewModel? was expected
و این در شرایطی هست که مسیر پکیج ویو مدل رو مطمعنم در xml درست کپی کردم ممنون میشم اگر راهنمایی بفرمایید
مصطفی آصفی –
سلام به شما. احتمالا این خطا رو به دلیل استفاده از حروف بزرگ (Uppercase) در نام پکیجتون دریافت کردید. در نام گذاری پکیج ها از حروف بزرگ استفاده نکنید.
امین دهقان (خریدار محصول) –
سلام روز به خیر مهندس
فرمودین حدود یک هفته دیگه انشالله کار کامل میش
اما هنوز خبری نشده
امکان داره تاریخ دقیق بدین؟
بی صبرانه منتظریم
ممنون
مصطفی آصفی –
سلام مهندس عزیز. همین الان که این متن رو می نویسم قتقریبا کار کامل شده.
به لحاظ زمان بندی موضوع اینه که من هر درس رو اونقدر ضبطش رو تکرار می کنم که کاملا حس کنم خوب شد. به همین دلیل همیشه کمی تاخیر رو دارم. ولی انشالله این دوره ظرف فردا یا پس فردا کامل میشه.
ممنون از همراهی شما
امین دهقان (خریدار محصول) –
سلام مهندس تبریک میگم به شما که انقد دقیق و روان آموزش میدین
به نظرم آموزش شما واقعا استاندارد هست .
میدونم زحمت زیادی هم برای بخش سمعی بصری (بدون توپوق و صدای با گیفیت و نمایش تصاویر ساده و پر معنا) می کشید
با قیمت بسیار نازل (البته قیمت مادی)که به نظرم انگیزه شما بیشتر کمک به پیشرفت برنامه نویسان هست و انگیزه مالی خیلی کمی دارید و در این شرایط اقتصادی این موضوع واقعا جای تشکر دارد.
چند سوال داشتم
یک) فصل ششم کی آماده میشه؟
دو) آیا Room رو با معماری MVVM آموزش میدین؟
سه) ارتباط با سرور کی آماده میشه؟
چهار) ارتباط با سرور در فصل ششم قرار دارد ؟
پنج) retRofit هست؟
شش) اگر رتروفیت هست آیا retRofit رو هم با معماری MVVM آموزش میدین؟
ببخشین سوال هام زیاد شد
مصطفی آصفی –
سلام به شما آقای دهقان. در رابطه با خواستههای شما، دو آموزش پایین هم به همین سبک ادامه پیدا کرد و منتشر شد:
آموزش رتروفیت در اندروید برای کار با API و معماری MMV (+) آموزش ساخت نمای سفارشی در اندروید و معماری MVVM (+)
ممنونم از محبتتون و انرژیای که دادین.
پینوشت: آموزش ROOM در اندروید با معماری MVVM (+) هم که پیشتر منتشر شده بود و بنده این نظر رو با دورههای جدید بهروز کردم.
سعید (خریدار محصول) –
بعد از دیدن آموزش رفتم سراغ چنتا اموزش دیگه. یه کاریو که شما انجام میدادید راه اصولی ترش بود . میگم که دوستان هم استفاده کنن.
لازم نیست برای متغیر های MutableLiveData حتما یه متغیر کمکی از جنس liveData بسازیم تا از بقیه کلاس ها قابل تغییر نباشه.
فقط کافیه یه متد getter براش بسازیم. جالبیش اینه که داخل xml هم هر دو حالت دسترسی داریم به متغیر . یعنی مثلا هم
gameViewModel.score
و هم
gameViewModel.getScore
مصطفی آصفی –
سلام و بسیار ممنون از شما برای مشارکت خوبتون.
LiveData رو برای جلوگیری از جهش بایستی ساخت.
در توسعه در هر صورت راههای مختلفی هست.
راهی که بنده گفتم روشی بود که مدرس گوگل در دوره آموزشی معماری MVVM گوگل در مجموعه یوداسیتی توصیه میکنه.
saeed (خریدار محصول) –
بسیار دوره خوبی بود. فقط سوالی که برای بنده پیش اومد مگر معماری MVVM شامل MODEL نمیشه . پس چرا هیچ اشاره ای به مدل نشد؟
مصطفی آصفی –
سلام به شما. خوشحالم که براتون مفید بوده. مباحث معماری MVVM در ادامه در فصل آینده با بحث دیتابیس ROOM روشنتر خواهد شد.
بهمن (خریدار محصول) –
سلام بنده امتیاز عالی به این ویدیو دادم! ولی یه انتقاد قرص و محکم دارم
در کامنت های فصل قبل عرض کردم از نویگیشن شناختی نداشتم دوره شما رو دیدم خیلی خوب بود فصلهای دیگه رو گرفتم و حداقل یه نکته از هر فصل یاد گرفتم ولی تو این فصل هیچ چیز جدیدی یاد نگرفتم! متاسفانه شما نکاتی که برایم مبهم بود و منتظرشون بودم رو جا انداختید ، این موضوع از اونجایی میاد که شما دوره رو برای مخاطب عام پیش میبرید و به کسانی که خودشون مختصرا با توجه به سورس ها این معماری رو کار کردند توجهی ندارید(دلیل اشتیاق بنده به فصل نویکیشن هم همین بود)، اگر بخوام با توجه به دانشی که از سورس ها دریافت کردم…
خلاصه که منتظر آموزش Room با پرداختن به مطالب کلیدی و سطح بالا هستم وگرنه CRUD و Entity عام پسند و برای شروع هستند…
در انتها بازم عرض میکنم که آموزش شما از هر نظر قابل قیاس با هیچ آموزش فارسی موجودی نیست
مصطفی آصفی –
سلام به شما آقای شاهویسی. در رابطه با خواسته شما، دو آموزش پایین هم به همین سبک ادامه پیدا کرد و منتشر شد که حرفهای هستند:
آموزش رتروفیت در اندروید برای کار با API و معماری MVVM (+)
آموزش ساخت نمای سفارشی در اندروید و معماری MVVM (+)
آموزش ROOM در اندروید (+) هم که پیشتر کمی بعد از نظر شما منتشر شده بود و احتمالا بررسی کردید.
ممنون از لطف شما و این که برای ابراز محبتتون وقت گذاشتید.