در حال حاضر میتوان گفت که معماری MVVM در اندروید بهترین معماری برای پیاده سازی اپلیکیشنها در برابر معماری هایی مثل MVP یا MVC میباشد. در این آموزش، ما در برنامهی اندروید خود به بحث و پیاده سازی الگوی معماری MVVM اندروید خواهیم پرداخت. در این مقاله همراه سون لرن باشید تا با آموزش معماری MVVM در اندروید، اولین اپلیکیشن خود را پیاده سازی کرده و با مزایای آن آشنا شوید.
MVVM مخفف Model، View، ViewModel میباشد. Model، View، ViewModel (یعنی MVVM) یک الگوی معماری برنامه است که توسط جان گاسمن به عنوان جایگزینی برای الگوهای MVC و MVP هنگام استفاده از فناوری Data Binding پیشنهاد شده است. برای شروع، توضیحات این الگو را در نظر میگیریم و هر یک از اجزای آن را تحلیل میکنیم. MVVM یک الگوی طراحی معماری نرم افزار است که جداسازی رابط کاربری از business logic و مدل داده (data model) برنامه را تسهیل میبخشد.
مدل (Model)
لایهی مدل میتواند شامل دسترسی به دادهها (Repository (مخازن) ، DAOها ، API ها)، کلاسهای Entity و ... باشد. مدل یک ارائه دهندهی داده و برای بروزرسانی دادهها است. دادهها را میتوان از منابع مختلف بازیابی کرد، به عنوان مثال:
REST API
Realm db
SQLite db
Handles broadcast
Shared Preferences
Firebase
و ...
مدل از View یا ViewModel چیزی نمیداند و به طور مستقل وجود دارد. اگر یک برنامهی اندرویدی که قبلاً بر اساس الگوی MVC یا MVP ساخته شده است، به MVVM انتقال دهید، لایهی مدل به احتمال زیاد نیازی به تغییر نخواهد داشت.
ویو (View)
View همان چیزی است که کاربر میبیند و در برنامه نویسی اندروید Viewها به طور معمول در XML تعریف میشوند و بیشتر در کلاسهای Fragment ،Activity یا View مشاهده میشوند. در بسیاری از برنامههای اندرویدی اغلب کدهایی که با View مرتبط نیستند ، به خصوص business logic، با Fragmentها و Activityها درهم میشوند، که میتواند باعث توسعه یا نگهداری بسیار دشوار باشد. MVVM با نگه داشتن Fragmentها و Activityها صرفاً به عنوان بخشی از لایهی View، با این مشکل مقابله میکند، آنها فقط باید وظیفهی تنظیم View را بر عهده بگیرند، و همچنین ViewModel را به View (با ابزارهایی مانند RxJava) متصل میکنند. برخلاف View ،MVC در مورد مدل اطلاعی ندارد. ویو تنها از ViewModel آگاه است که با آن دادههای خود را برای نمایش پر میکند. View باید عاری از منطق نمایش (قالب بندی تاریخ ، قوانین برای نشان دادن / پنهان کردن یک عنصر و موارد دیگر) باشد، که به جای آن در ViewModel حضور خواهد داشت. View میتواند از ViewModel درخواست کند تا عملیاتی را انجام دهد، که معمولاً ممکن است مدل را بر اساس ورودی کاربر بروز کند. برای مثال View مسئول رسیدگی به عنوانهای زیر است:
Menus
Permissions
Event listeners
Showing dialogs, Toasts, Snackbars
Working with Android View and Widget
Start Activities
All functionality which is related to the Android Context
ویو مدل (ViewModel)
ViewModel شامل دادههای مورد نیاز برای View است. همانطور که از نام آن مشخص شده است، ViewModel پل ارتباطی بین View و Model است. دادههای خود را از لایه مدل بیرون میکشد و آن را برای نمایش تبدیل میکند. ViewModel حالت فعال برنامه را در خود نگهداری میکند. این عملیات را در معرض View قرار میدهد و interface را برای بروز کردن مدل فراهم میکند. ViewModelها نوعی POJO هستند، به این معنی که به راحتی قابل آزمایش هستند که یکی از اصلیترین مزایای آنها میباشد. ViewModel مسئولیتهای زیر را داراست:
Exposing data
(Exposing state (progress, offline, empty, error, etc
Handling visibility
Input validation
Executing calls to the model
Executing methods in the view
ViewModel فقط باید دربارهی Context برنامه آگاهی داشته باشد. Context برنامه میتواند شامل:
Start a service
Bind to a service
Send a broadcast
Register a broadcast receiver
Load resource values
و نمیتواند شامل کارهای زیر باشد:
Show a dialog
Start an activity
Inflate a layout
تفاوت MVVM با MVP:
ViewModel به جای Presenter در لایهی میانی مینشیند.
Presenter اشاراتی به View دارد. ViewModel به این صورت نمیباشد.
ViewModel جریان داده (data streams) را ارسال میکند.
Presenter و View در یک رابطهی 1 به 1 هستند.
View و ViewModel در یک رابطهی 1 به تعدادی زیاد قرار دارند.
ViewModel نمیداند که View در حال گوش دادن به آن است.
تفاوت MVVM با MVC:
MVVM دارای چندین مفهوم با الگوی رایجتر (MVC (Model View Controller است، بنابراین کسانی که قبلاً با MVC آشنا بودند یا با آن کار کرده بودند باید بتوانند با MVVM به راحتی کار کنند. Model و ViewModel در MVVM یکسان است همانطور که در MVC وجود دارد، آنچه متفاوت است نحوهی برقراری ارتباط و همچنین آگاهی آنها از یکدیگر است.
مزایای MVVM
Viewmodels امکان آزمایش آسانتر Display Logic را فراهم میآورد:
Viewmodels اجازه میدهد تا منطق صفحه نمایش بدون اینکه لحظه به لحظه مشاهده شود آزمایش شود. در توسعهی Android،این اجازه را میدهد تا تستهای بیشتری در JUnit نوشته شود و به صورت محلی (local) اجرا شود، نه در Android JVM (شبیه ساز یا دستگاه)، به این معنی که تستها خیلی سریعتر اجرا میشوند.
تفکیک روابط
کدهای درهم و شکننده باعث کابوس نگهداری برنامه میشود. اگرما بدون داشتن هیچگونه معماری، توسعه دادن یک اپلیکیشن را شروع کنیم باعث بروز بیشتر انواع ارور یا خطا در برنامه میشویم و وقتی که بخواهیم یک features جدید به برنامه اضافه کنیم سردرگم میشویم و سرعت توسعه یافتن برنامه خیلی کم میشود و باعث میشود که مشتری از روند توسعهی برنامه ناراضی باشد. يكی از مهم ترين مزایای اين امر كه ما اغلب در برنامههای اندرویدی میبينیم، Activityها وFragmentهای يكپارچه است که شامل business logic، تعامل مستقيم با پايگاه داده و یا API است، كه با كليهی كدهای View همراه است. MVVM کمک زیادی میکند تا معماری تمیز، منسجم و کاملاً جفت شده، حفظ شود و Activityها و Fragmentها را صرفاً به عنوان بخشی از View نگه میدارد.
استفادهی مجدد از کد را بهبود میبخشد
Viewmodels را میتوان دوباره در سراسر برنامه استفاده کرد، به این معنی که display logic نیازی به کپی ندارد. این View حتی میتواند برای جایی دیگر جابهجا شود و هنوز از همان ViewModel استفاده میکند و تا زمانی که به همان دادهها و عملیات بستگی داشته باشد، از همان ViewModel استفاده میکند.
رابط کاربری میتواند بدون دست زدن به Business Logic بروز شود
این به این معنی است که توسط سازندگان مختلف و درگیریهای کمتری میتوان روی مؤلفهها (Components) کار کرد، و این امکان را فراهم میکند تا تعداد اعضای تیم راحتتر افزایش یابد. به عنوان مثال، یک توسعه دهنده front-end قادر است بدون نیاز به منطق در ViewModel، به طور مستقل روی View کار کند، در حالی که توسعه دهنده ای دیگر بر روی بخشی دیگر کار میکند و یک نسخهی fake از یک ViewModel میتواند مورد استفاده قرار گیرد در حالی که نسخهی اصلی در حال توسعه است.
در این مقاله، ما از Data Binding استفاده خواهیم کرد. Data Binding Library توسط Google به منظور پیوند دادن دادهها به طور مستقیم در Xml Layout معرفی شده است. ما میخواهیم یک مثال ساده از برنامهی ورود به صفحه (Log in) که ورودی را از کاربر درخواست میکند ایجاد کنیم. خواهیم دید که ViewModel چگونه به View اعلام میکند که چه زمانی پیام (Toast) را بدون نگه داشتن یا مراجعه به View، نمایش دهد. چگونه میتوان بدون مراجعه به آن، به برخی از کلاسها اطلاع داد؟ این کار به سه روش مختلف قابل انجام است:
با استفاده از Two Way Data Binding
با استفاده از LiveData
با استفاده از RxJava
Two Way Data Binding Two Way Data Binding یک تکنیک برای اتصال اشیاء شما به Xml Layout است به گونه ای که Object و Layout میتوانند هر دو داده را برای یکدیگر ارسال کنند. در مثال ما، ViewModel میتواند دادهها را به طرح بفرستد و همچنین تغییرات را مشاهده کند. برای این کار، به یک BindingAdapter و custom attribute نیاز داریم که در XML تعریف شده است. BindingAdapter میتواند به تغییر در ویژگی گوش دهد. از طریق مثال زیر در مورد Two Way Data Binding بیشتر میآموزیم.
مثالی از ساختار پروژهی MVVM در اندروید
افزودن کتابخانهی Data Binding
کد زیر را به فایل build.gradle برنامهی خود اضافه کنید:
android {
dataBinding {
enabled = true
}
}
این قابلیت اتصال داده (Data Binding) را در برنامهی شما فعال میکند.
اضافه کردن وابستگی ها
وابستگیهای زیر را در فایل build.gradle خود اضافه کنید:
در اینجا ViewModel ما دادهها را به View متصل میکند. ()viewModel.onLoginClicked<-() این دکمه به صورت lambda در ViewModel تعریف و فراخوانی میشود. {bind: toastMessage = "@ {viewModel.toastMessage" یک ویژگی سفارشی است که ما برای اتصال داده دو طرفه (two-way data binding) ایجاد کرده ایم. با توجه به تغییراتی که در toastMessage در ViewModel ایجاد میشود، BindingAdapter در View فعال میشود.
ViewModel
کد ورود به سیستم LoginViewModel.java در زیر آورده شده است:
package com.journaldev.androidmvvmbasics.viewmodels;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.text.TextUtils;
import android.util.Patterns;
import com.android.databinding.library.baseAdapters.BR;
import com.journaldev.androidmvvmbasics.model.User;
public class LoginViewModel extends BaseObservable {
private User user;
private String successMessage = "Login was successful";
private String errorMessage = "Email or Password not valid";
@Bindable
private String toastMessage = null;
public String getToastMessage() {
return toastMessage;
}
private void setToastMessage(String toastMessage) {
this.toastMessage = toastMessage;
notifyPropertyChanged(BR.toastMessage);
}
public void setUserEmail(String email) {
user.setEmail(email);
notifyPropertyChanged(BR.userEmail);
}
@Bindable
public String getUserEmail() {
return user.getEmail();
}
@Bindable
public String getUserPassword() {
return user.getPassword();
}
public void setUserPassword(String password) {
user.setPassword(password);
notifyPropertyChanged(BR.userPassword);
}
public LoginViewModel() {
user = new User("","");
}
public void onLoginClicked() {
if (isInputDataValid())
setToastMessage(successMessage);
else
setToastMessage(errorMessage);
}
public boolean isInputDataValid() {
return !TextUtils.isEmpty(getUserEmail()) && Patterns.EMAIL_ADDRESS.matcher(getUserEmail()).matches() && getUserPassword().length() > 5;
}
}
کلاس فوق همچنین میتواند ViewModel را گسترش دهد. اما ما به BaseObservable احتیاج داریم زیرا دادهها را به جریان تبدیل میکند و وقتی ویژگی toastMessage تغییر میکند، آگاه میشود. برای ویژگی سفارشی toastMessage که در XML تعریف شده است، باید Setter و Getter را تعریف کنیم. در داخل Setter، به Observer اطلاع میدهیم که دادهها تغییر کرده اند.View ما (activity ما) میتواند اقدام مناسب را تعریف کند.
به لطف DataBinding، کلاس ActivityMainBinding از Layout به صورت خودکار ایجاد میشود. هرگاه خصوصیات toastMessage تعریف شده در دکمه تغییر کند، متد BindingAdapter فعال میشود. باید از همان صفتی که در XML و ViewModel تعریف شده استفاده کند. بنابراین در برنامهی فوق، ViewModel با گوش دادن به تغییرات در View ، مدل را بروز میکند. همچنین، مدل با استفاده از notifyPropertyChanged میتواند View را از طریق ViewModel بروز کند. خروجی برنامهی فوق را در زیر میتوانید مشاهده کنید.
شما میتوانید پروژهی آموزش MVVM در Android با استفاده از DataBinding را از لینک ذکر شده در زیر دانلود کنید.
برنامه بسیار ساده است، پستهای برتر Reddit را از API JSON آن میآورد و آنها را در یک لیست نمایش میدهد.
در این مثال از کتابخانههای زیر استفاده شده است:
RxJava
Retrofit
Dagger 2
Picasso
AndroidAnnotations
Lombok
شما میتوانید این مثال را در لینک زیر مشاهده کنید: (Github(Mvvm-Reddit جمع بندی در این مقاله با معماری MVVM در اندروید آشنا شدیم. آن را با معماری MVC و معماری MVP مقایسه کردیم. ما با ویژگیها و کارایی MVVM آشنا شدیم و فهمیدیم که استفاده از آن پر کاربرد و مفید است و یک مسیر کلی به اپلیکیشن ما میدهد و باعث میشود که خیلی راحت ما به برنامهی خود Feature جدید اضافه کنیم و تست پذیری بالایی به برنامه ما میدهد و نگهداری برنامه را بهبود میبخشد. امیدواریم این مقاله برای شما مفید باشد اگه سوالی داشتید با ما و کاربران سون لرن به اشتراک بگذارید. منابع این مقاله www.journaldev.com www.codevate.com
اگر به یادگیری بیشتر در زمینهی برنامه نویسی اندروید علاقه داری، با شرکت در دورهی آموزش برنامه نویسی اندروید در کمتر از یکسال به یک توسعهدهنده اندروید همه فن حریف تبدیل میشوی که آمادهی استخدام، دریافت پروژه و حتی پیادهسازی اپلیکیشن خودت هستی.
۱۵ دیدگاه
۰۵ دی ۱۴۰۰، ۱۵:۴۶
سلام اون viewModel.userEmail و viewModel.userPassword که در فایل لایوت استفاده کردید در هیچ جای کلاس ویو مدل تعریف نشده، پس چجور دارید ازش استفاده میکنید؟
نازنین کریمی مقدم۰۶ دی ۱۴۰۰، ۰۷:۱۴
درود
در viewModel ما از یک بایندینگ استفاده میکنیم و در حقیقت اونجا داریم این دو رو به لی اوت متصل میکنیم.
برای توضیح دقیقتر میتونید ویدیو شو در نت یا منابعی که پایین مطلب زدیم ببینید.
برقرار باشید.
رضا۱۰ مهر ۱۴۰۰، ۱۴:۰۰
سلام وقتتون بخیر
یه سوال داشتم اونم این که برای استفاده از checkbox, radiobutton, switch و ... چطور باید مقادیرشون رو دریافت کرد توی این معماری
اگه یه توضیح بدید یا مقاله ای در این مورد معرفی کنید ممنون میشم
نازنین کریمی مقدم۱۲ مهر ۱۴۰۰، ۱۱:۲۹
درود بر شما سوال بسیار خوبی پرسیدید
چنین مقاله ای در تقویم محتوایی ما هست. اما برای اینکه زودتر جوابتون رو بگیرید و منتظر نباشید، پیشنهاد میکنم <a href="https://stackoverflow.com/questions/11064888/mvvm-binding-to-check-box-if-checkbox-checked/11065381" target="_blank" rel="noopener nofollow ugc">این نمونه</a> رو بررسی کنید.
احمد۲۴ فروردین ۱۴۰۰، ۰۲:۰۳
سلام ببخشید من یک سوال داشتم. اگر بخواهیم یک intent ارسال کنیم با یک اکشنی مثل send این باید تو view model نوشته شود یا اطلاعات مورد نیاز در view دریافت شود و آنجا ارسال شود؟
ممنون
نازنین کریمی مقدم۲۴ فروردین ۱۴۰۰، ۱۷:۵۹
سلام.
جواب سوالتون رو به صورت کامل و تصویری میتونید از اینجا بگیرید: <a href="https://medium.com/android-news/its-time-to-use-mvvm-as-your-android-s-app-base-architecture-part-1-cf0ce2542b48" target="_blank" rel="noopener nofollow ugc">مثال از mvvm در اندروید</a>
مهیار مجیدی۰۳ آذر ۱۳۹۹، ۱۶:۵۵
مقاله سازنده ایی بود
البته پیاده سازی این مدل برای اپلیکیشنها متفاوته .. یکی از RXJava استفاده میکنه یکی از LiveData . البته در ویدئوهای اموزشی یودمی و یا یوداسیتی به صورت متفاوتتر و جامعتر اموزش داده شده
معمولا آموزشهای متفاوت رو باید دوستان ببینن و نهایتا خودشون تصمیم بگیرن به چ صورت باید نرم افزار رو ببرن جلو
MVI مدل جدیدتر از MVVM . خوشحال میشم مقاله ایی در این رابطه در سایت شما مطالعه کنم
نازنین کریمی مقدم۰۴ آذر ۱۳۹۹، ۰۹:۱۳
سلام. ممنون از اینکه با ما همراه هستید.
پیشنهادتون بررسی میشه و در صورت امکان یه مقاله هم برای MVI خواهیم داشت.
مرتضی۱۵ آبان ۱۳۹۹، ۱۸:۴۳
بسیار عالی و خوب بود تشکر از شما
سحر۰۳ آبان ۱۳۹۹، ۰۵:۱۸
سلام.مقاله خوبی بود.مفید و ساده.ممنون از شما
علی۱۷ مهر ۱۳۹۹، ۱۶:۱۲
با سلام
بسیار روان و ساده بود،خیلی ممنون از سایت خوبتون و مطالبی که زحمت میکشین برای ما قرار میدین.
علی۰۳ مهر ۱۳۹۹، ۱۱:۴۵
واقعا افتضاح بود.
فقط زحمت ترجمه تحت اللفظی رو کشیدید. گوگل ترانسلیت هم میتونست این کار رو بکنه. هر چیزی که توی سایت خارجی اصلی گفته شده رو بصورت خیلی بد ترجمه کردید. بدون کوچکترین توضیح اضافی و روشن کردن مطلب.
فقط باعث سردرگمی من شد.
به هر حال موفق باشید.
نازنین کریمی مقدم۰۴ مهر ۱۳۹۹، ۱۵:۵۵
سلام.
اگر دقیقتر توضیح بدید که در چه بخشهایی برای شما نامفهوم بوده، سعی میکنیم در مقالات بعدی در آن بخشها روشنتر صحبت کنیم.
به دلیل حفظ مفاهیم تاجایی که شده از عبارات انگلیسی و لاتین کمک گرفتیم، اما هدف این بوده که شما معماری MVVM رو متوجه بشید. در هر قسمتی از فهم مقاله که دچار سردرگمی شدید بپرسید، ما بیشتر توضیح خواهیم داد.
behrooz۲۱ مرداد ۱۳۹۹، ۰۹:۱۳
ممنون از مقاله خوب و سلیس بودن . امیدوارم همیشه به همین صورت مقاله بهتری نشر بدین
امیر حسین حیدری۲۴ مرداد ۱۳۹۹، ۱۱:۳۸
سلام دوست عزیز از این که مقاله واستون مفید بوده خوشحالیم، موفق باشید
شروع رایگان یادگیری برنامه نویسی
کلیک کنید 👇
دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد: