آموزش الگوی معماری MVVM در اندروید
آشنایی با MVVM
Model — View — ViewModel (MVVM) الگوی معماری نرمافزار شناختهشده در برنامهنویسی اندروید است که بر تمام اشکالات الگوهای طراحی MVP و MVC غلبه میکند. MVVM پیشنهاد میکند که منطق ارائه دادهها Views یا UI را از بخش منطق تجاری اصلی برنامه جدا کنید. در ادامه با معماری MVVM بهخوبی آشنا میشویم و آموزش MVVM را باهم موردبررسی قرار میدهیم.
توسعهدهندگان اندروید و سایر پلتفرمها همیشه یک کد تمیز و ساختاریافته را برای پروژهها ترجیح میدهند. سازماندهی کدها بر اساس الگوی طراحی به نگهداری بهتر نرمافزار کمک میکند. همچنین با آگاهی از تمام بخشهای منطقی برنامه اندروید، اضافه کردن و حذف ویژگیهای برنامه آسانتر است. علاوه بر این، الگوهای طراحی یا معماری اندروید همچنین تضمین میکنند که تمام کدها در تست واحد بدون دخالت کلاسهای دیگر پوشش داده میشوند.
انواع معماریها در اندروید
وقتی توسعهدهندگان روی یک اپلیکیشن موبایل واقعی کار میکنند که ماهیت آن پویا است و ویژگیهای آن را بر اساس نیاز کاربر گسترش میدهد، در این صورت امکان نوشتن منطق اصلی در فعالیتها یا قطعات وجود ندارد. برای ساختار کد پروژه و دادن طرحی مدولار به آن (قطعات کد مجزا)، الگوهای معماری اندروید برای جداسازی نگرانیها اعمال میشود. محبوبترین معماریهای اندرویدی که توسط توسعهدهندگان استفاده میشود به شرح زیر است:
- MVC (Model — View — Controller)
- MVP (Model — View — Presenter)
- MVVM (Model — View — ViewModel)
ایده اصلی همه این الگوها این است که پروژه را به روشی مناسب سازماندهی کنیم تا همه کدها در تست واحد پوشش داده شوند. علاوه بر این، افزودن و حذف ویژگیها در نگهداری نرمافزار بسیار آسانتر است و توسعهدهندگان میتوانند بخشهای مختلف منطقی حیاتی را پیگیری کنند.
معماری اندروید Model-View-Controller (MVC)
معماری MVC قدیمیترین معماری اپلیکیشن اندروید است که بهسادگی پیشنهاد میکند کد را به ۳ لایه مختلف جدا کنید:
- مدل (Model): لایهای برای ذخیرهسازی دادهها است. مسئولیت رسیدگی به منطق دامنه (قوانین کسبوکار در دنیای واقعی) و ارتباط با پایگاه داده و لایههای شبکه را بر عهده دارد.
- نمایش(View): لایه UI (رابط کاربری). تجسم دادههای ذخیرهشده در مدل را فراهم میکند.
- کنترلکننده(Controller): لایهای که حاوی منطق هسته است. از رفتار کاربر مطلع میشود و مدل را بنا به نیاز بهروز میکند.
در مدل معماری اندروید MVC، View و Controller هر دو به مدل بستگی دارند. دادههای برنامه توسط کنترلر بهروز میشود و View دادهها را دریافت میکند. در این الگو، مدل را میتوان مستقل از رابط کاربری که جدا میشود، آزمایش کرد.
چندین روش برای اعمال الگوی MVC وجود دارد. فعالیتها و قطعات میتوانند مانند کنترلکننده عمل کنند، جایی که مسئولیت پردازش دادهها و بهروزرسانی نماها را بر عهدهدارند. راه دیگر این است که از Activity ها و Fragment ها بهعنوان Views استفاده کنید و کنترلر و همچنین Models باید یک کلاس جداگانه باشد که هیچ کلاس Android را گسترش ندهد.
اگر Views به اصل مسئولیت واحد پایبند باشد، نقش آنها فقط بهروزرسانی کنترلر برای هر رویداد کاربر و نمایش دادهها از مدل بدون اجرای هیچ منطق تجاری است. در این مورد، تستهای UI باید برای پوشش عملکردهای View کافی باشد.
مزایای معماری MVC
- الگوی MVC تست پذیری کد را افزایش میدهد و پیادهسازی ویژگیهای جدید را آسانتر میکند، زیرا از جداسازی نگرانیها بسیار پشتیبانی میکند.
- آزمایش واحد مدل و کنترلر امکانپذیر است زیرا آنها از هیچ کلاس Android استفاده نمیکنند.
- درصورتیکه View به اصل مسئولیت واحد (بهروزرسانی کنترلکننده و نمایش دادهها از مدل بدون اجرای منطق دامنه) احترام بگذارد، عملکردهای View را میتوان از طریق تستهای UI بررسی کرد.
معایب:
- لایههای کد به یکدیگر بستگی دارند حتی اگر MVC بهدرستی اعمال شود.
- هیچ پارامتری برای مدیریت منطق UI، یعنی نحوه نمایش دادهها وجود ندارد.
معماری اندروید Model-View-Presenter (MVP).
معماری اندروید MVP دومین تکرار معماری اپلیکیشن اندروید است. این الگو بهطور گسترده پذیرفتهشده است و همچنان برای توسعهدهندگان آینده توصیه میشود. یادگیری آن به نسبت مدل معماری بالا آسانتر است.
- مدل(Model): لایهای برای ذخیرهسازی دادهها. مسئولیت رسیدگی به منطق دامنه (قوانین کسبوکار در دنیای واقعی) و ارتباط با پایگاه داده و لایههای شبکه را بر عهده دارد.
- نمایش (View): لایه UI (رابط کاربری). تجسم دادهها را فراهم میکند و عملکرد کاربر را بهمنظور اطلاع دادن به ارائهکننده پیگیری میکند.
- ارائهدهنده (Presenter): دادهها را از مدل واکشی میکند و منطق UI را برای تصمیمگیری در مورد نمایش دادن اعمال میکند. وضعیت View را مدیریت میکند و طبق اعلان ورودی کاربر از View اقداماتی را انجام میدهد.
در طرحواره MVP، View و Presenter ارتباط نزدیکی دارند و به یکدیگر ارجاع دارند. برای خوانایی کد و درک آسانتر، از کلاس رابط Contract برای تعریف رابطه Presenter و View استفاده میشود. این معماری اندروید نمای انتزاعی است و دارای یک رابط است تا ارائهدهنده را برای تست واحد فعال کند.
مزایای معماری اندروید MVP:
- هیچ رابطه مفهومی در اجزای اندروید وجود ندارد
- نگهداری و آزمایش کد آسان بهعنوان مدل، نمای و لایه ارائهدهنده برنامه از هم جداشده است.
معایب معماری MVP:
اگر توسعهدهنده از اصل مسئولیت واحد برای شکستن کد پیروی نکند، لایه Presenter تمایل دارد تا به یک کلاس بزرگ همهچیز گسترش یابد.
معماری اندروید Model—View—ViewModel (MVVM)
سومین تکرار معماری اندروید الگوی MVVM است که در این مقاله هدف اصلی ما نیز آموزش MVVM در اندروید است. در حین انتشار اجزای معماری اندروید، تیم اندروید این الگوی معماری را توصیه کرد. در این قسمت قصد داریم آموزش MVVM را با ارائه یک نمونه عملی در اندروید استودیو ارائه دهیم؛ اما قبل از اینکه به سراغ ساخت اپلیکیشن، ابتدا بهخوبی باید با معماری MVVM آشنا باشیم.
Model-View-ViewModel (MVVM) یک الگوی طراحی نرمافزاری است که برای جداسازی منطق برنامه و کنترلهای رابط کاربری ساختهشده است. MVVM همچنین بهعنوان model-view-binder شناخته میشود و توسط معماران مایکروسافت کن کوپر و جان گاسمن ساختهشده است.
مانند بسیاری از الگوهای طراحی دیگر، MVVM به سازماندهی کد و تبدیل برنامهها به ماژولها کمک میکند تا توسعه، بهروزرسانی و استفاده مجدد از کد را سادهتر و سریعتر کند. این الگو اغلب در ویندوز و نرمافزارهای ارائه گرافیک وب استفاده میشود.
لایههای معماری MVVM اندروید
در این بخش از آموزش MVVM همانند معماری بالا که در رابطه با آنها صحبت کردیم، معماری MVVM اندروید نیز از سه جزء اصلی زیر تشکیلشده است.
- مدل: این لایه وظیفه انتزاع منابع داده را بر عهده دارد. Model و ViewModel برای دریافت و ذخیره دادهها باهم کار میکنند.
- View: هدف این لایه اطلاعرسانی به ViewModel در مورد عملکرد کاربر است.
- ViewModel: جریانهای دادهای را که مربوط به View هستند را نشان میدهد.
معماری MVVM و MVP کاملاً مشابه هستند زیرا هر دو در انتزاع وضعیت و رفتار لایه View کارآمد هستند. در MVVM، Views میتواند خود را به جریانهای دادهای که توسط ViewModel در معرض دید قرار میگیرد، متصل کند.
در طرحواره MVVM View به ViewModel در مورد اقدامات مختلف اطلاع میدهد. View ارجاعی به ViewModel دارد درحالیکه ViewModel هیچ اطلاعاتی در مورد View ندارد. رابطه چند به یک که بین View و ViewModel وجود دارد و MVVM از اتصال داده دوطرفه بین هر دو پشتیبانی میکند.
ویژگیهای معماری MVVM
الگوی MVVM شباهتهایی با الگوی طراحی MVP (Model — View — Presenter) دارد زیرا نقش Presenter توسط ViewModel ایفا میشود. بااینحال، اشکالات الگوی MVP توسط MVVM بهروشهای زیر حلشده است:
- ViewModel هیچ نوع ارجاعی به View ندارد.
- رابطه بین View و ViewModel بسیار به ۱ وجود دارد.
- هیچ روش راهاندازی برای بهروزرسانی View وجود ندارد.
مزایای معماری MVVM
معماری MVVM نقاط قوت بسیار زیادی نسبت به دو معماری قبل خودش را دارد. در این بخش از آموزش MVVM به مزایای MVVM میپردازیم.
- توسعهدهندگان میتوانند برنامههایی را طراحی کنند که میتوانند تغییرات را در آینده بپذیرند.
- یک طراحی ماژولار به برنامه میدهد که تست کیفیت و نگهداری کد را تضمین میکند.
- افزایش قابلیت استفاده مجدد کد
- همه ماژولها مستقل هستند که تست پذیری هر لایه را بهبود میبخشد.
- فایلهای پروژه را قابل نگهداری و ایجاد تغییرات آسان میکند.
معایب معماری MVVM
هرچند معماری اندروید MVVM مزایای بسیار زیادی دارد، اما این به این معنی نیست که این معماری کامل است. این معماری نیز معایبی دارد که در این بخش از آموزش MVVM به آن میپردازیم.
- نوشتن کل کد پروژه در یک الگوی معماری فرآیندی زمانبر است.
- نظم و انضباط دقیق از طرف تیم توسعهدهنده موردنیاز است زیرا یک تغییر نابجا میتواند یکپارچگی معماری را خراب کند.
- این الگوی طراحی برای پروژههای کوچک ایده آل نیست.
- اگر منطق اتصال دادهها خیلی پیچیده باشد، اشکالزدایی برنامه کمی سختتر خواهد شد.
راههای پیادهسازی MVVM در پروژه
در این بخش از آموزش MVVM به راههای پیادهسازی MVVM میپردازیم. ۲ راه برای پیادهسازی الگوی طراحی یا معماری MVVM در پروژههای اندرویدی وجود دارد:
- با استفاده از کتابخانه DataBinding منتشرشده توسط Google
- استفاده از هر ابزاری مانند RxJava برای DataBinding.
اتصال دادهها یا DataBinding برای پیادهسازی MVVM:
Google کتابخانه Data Binding را برای اندروید منتشر میکند که به توسعهدهندگان اجازه میدهد اجزای رابط کاربری را در طرحبندیهای XML با مخازن دادههای برنامه متصل کنند. این کار به حداقل رساندن کد منطق برنامه اصلی که با View متصل میشود کمک میکند. علاوه بر این، دوطرفه Data Binding برای اتصال اشیاء به طرحبندیهای XML انجام میشود تا شی و طرحبندی هر دو بتوانند دادهها را به یکدیگر ارسال کنند. این نکته را میتوان با مثال این آموزش MVVM به تصویر کشید.
Syntax for the two way data binding is @={variable}
نمونهای از الگوی معماری MVVM
در اینجا یک مثال از یک برنامه اندرویدی User-Login برای نشان دادن اجرای الگوی معماری MVVM در پروژهها آورده شده است. در این بخش از آموزش MVVM به پیادهسازی عملی این معماری میپردازیم. برنامه از کاربر میخواهد شناسه ایمیل و رمز عبور را وارد کند. بر اساس ورودیهای دریافت شده، ViewModel به View اطلاع میدهد که چه چیزی را بهعنوان یک پیام تست نشان دهد. ViewModel ارجاعی به View نخواهد داشت.
برای فعال کردن DataBinding در برنامه اندروید، کدهای زیر باید در فایل build.gradle(build.gradle (:app)) برنامه اضافه شوند:
Enable DataBinding:
android {
dataBinding {
enabled = true
}
}
اضافه کردن وابستگی چرخه عمر:
implementation ‘android.arch.lifecycle:extensions:1.1.1’
در زیر پیادهسازی کامل گامبهگام اپلیکیشن اندروید User-Login با الگوی MVVM آورده شده است.
پیادهسازی گامبهگام MVVM
این مرحله از آموزش MVVM شامل پیادهسازی اپلیکیشن اندرویدی در اندروید استودیو با استفاده از معماری MVVM است.
توجه: مراحل زیر در اندروید استودیو نسخه ۴٫۰ انجام میشود
مرحله ۱: ایجاد یک پروژه جدید
- روی File و سپس New => New Project کلیک کنید.
- یک پروژه خالی را انتخاب کنید
- زبان را بهعنوان Java/Kotlin انتخاب کنید
- حداقل SDK را بر اساس نیاز خود انتخاب کنید.
مرحله ۲: فایل String.xml را تغییر دهید
تمام رشتههایی که در اکتیویتی استفاده میشوند در این فایل فهرست شدهاند.
فایل xml:
<resources>
<string name=”app_name”>GfG | MVVM Architecture</string>
<string name=”heading”>MVVM Architecture Pattern</string>
<string name=”email_hint”>Enter your Email ID</string>
<string name=”password_hint”>Enter your password</string>
<string name=”button_text”>Login</string>
</resources>
مرحله ۳: ایجاد کلاس Model
در این مرحله از آموزش MVVM، یک کلاس جدید به نام Model ایجاد کنید که شناسه ایمیل و رمز عبور واردشده توسط کاربر را در آن نگهدارید. در زیر کد پیادهسازی کلاس Model مناسب است.
import androidx.annotation.Nullable;
public class Model {
@Nullable
String email,password;
// constructor to initialize
// the variables
public Model(String email, String password){
this.email = email;
this.password = password;
}
// getter and setter methods
// for email variable
@Nullable
public String getEmail() {
return email;
}
public void setEmail(@Nullable String email) {
this.email = email;
}
// getter and setter methods
// for password variable
@Nullable
public String getPassword() {
return password;
}
public void setPassword(@Nullable String password) {
this.password = password;
}
}
مرحله ۴: کار با فایل activity_main.xml
فایل activity_main.xml را بازکنید و ۲ EditText را اضافه کنید تا ورودیهای ایمیل و رمز عبور را دریافت کنید. یک دکمه ورود نیز برای تائید ورودی کاربر و نمایش پیام Toast مناسب موردنیاز است. در زیر کد طراحی یک طرح فعالیت مناسب آورده شده است.
توجه: برای عملکرد صحیح Data Binding Library، باید تگ layout را در بالا تنظیم کنید. تگ layout محدودیت XML در این مورد کار نخواهد کرد.
<?xml version=”1.0″ encoding=”utf-8″?>
<layout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:bind=”http://schemas.android.com/tools”>
<!– binding object of ViewModel to the XML layout –>
<data>
<variable
name=”viewModel”
type=”com.example.mvvmarchitecture.AppViewModel” />
</data>
<!– Provided Linear layout for the activity components –>
<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_gravity=”center”
android:layout_margin=”8dp”
android:background=”#168BC34A”
android:orientation=”vertical”>
<!– TextView for the heading of the activity –>
<TextView
android:id=”@+id/textView”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:text=”@string/heading”
android:textAlignment=”center”
android:textColor=”@android:color/holo_green_dark”
android:textSize=”36sp”
android:textStyle=”bold” />
<!– EditText field for the Email –>
<EditText
android:id=”@+id/inEmail”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginStart=”10dp”
android:layout_marginTop=”60dp”
android:layout_marginEnd=”10dp”
android:layout_marginBottom=”20dp”
android:hint=”@string/email_hint”
android:inputType=”textEmailAddress”
android:padding=”8dp”
android:text=”@={viewModel.userEmail}” />
<!– EditText field for the password –>
<EditText
android:id=”@+id/inPassword”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginStart=”10dp”
android:layout_marginEnd=”10dp”
android:hint=”@string/password_hint”
android:inputType=”textPassword”
android:padding=”8dp”
android:text=”@={viewModel.userPassword}” />
<!– Login Button of the activity –>
<Button
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginStart=”20dp”
android:layout_marginTop=”60dp”
android:layout_marginEnd=”20dp”
android:background=”#4CAF50″
android:fontFamily=”@font/roboto”
android:onClick=”@{()-> viewModel.onButtonClicked()}”
android:text=”@string/button_text”
android:textColor=”@android:color/background_light”
android:textSize=”30sp”
android:textStyle=”bold”
bind:toastMessage=”@{viewModel.toastMessage}” />
<ImageView
android:id=”@+id/imageView”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginTop=”135dp”
app:srcCompat=”@drawable/banner” />
</LinearLayout>
</layout>
مرحله ۵: ایجاد کلاس ViewModel
در این مرحله از آموزش MVVM به ایجاد کلاس ViewModel میپردازیم. این کلاس شامل تمام متدهایی است که برای فراخوانی در طرح برنامه لازم است. همچنین این کلاس، کلاس ViewModel BaseObservable را گسترش میدهد زیرا دادهها را به جریان تبدیل میکند و هنگام تغییر ویژگی پیام toast به View اطلاع میدهد.
import android.text.TextUtils;
import android.util.Patterns;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
public class AppViewModel extends BaseObservable {
// creating object of Model class
private Model model;
// string variables for
// toast messages
private String successMessage = “Login successful”;
private String errorMessage = “Email or Password is not valid”;
@Bindable
// string variable for
// toast message
private String toastMessage = null;
// getter and setter methods
// for toast message
public String getToastMessage() {
return toastMessage;
}
private void setToastMessage(String toastMessage) {
this.toastMessage = toastMessage;
notifyPropertyChanged(BR.toastMessage);
}
// getter and setter methods
// for email variable
@Bindable
public String getUserEmail() {
return model.getEmail();
}
public void setUserEmail(String email) {
model.setEmail(email);
notifyPropertyChanged(BR.userEmail);
}
// getter and setter methods
// for password variable
@Bindable
public String getUserPassword() {
return model.getPassword();
}
public void setUserPassword(String password) {
model.setPassword(password);
notifyPropertyChanged(BR.userPassword);
}
// constructor of ViewModel class
public AppViewModel() {
// instantiating object of
// model class
model = new Model(“”,””);
}
// actions to be performed
// when user clicks
// the LOGIN button
public void onButtonClicked() {
if (isValid())
setToastMessage(successMessage);
else
setToastMessage(errorMessage);
}
// method to keep a check
// that variable fields must
// not be kept empty by user
public boolean isValid() {
return !TextUtils.isEmpty(getUserEmail()) && Patterns.EMAIL_ADDRESS.matcher(getUserEmail()).matches()
&& getUserPassword().length() > 5;
}
}
مرحله ۶: قابلیتهای View را در فایل MainActivity تعریف کنید
کلاس View مسئول بهروزرسانی UI برنامه است. با توجه به تغییرات در پیام نان تست ارائهشده توسط ViewModel، آداپتور Binding لایه View را فعال میکند. تنظیمکننده پیام Toast به مشاهدهکننده (View) در مورد تغییرات دادهها اطلاع میدهد. پسازآن، View اقدامات مناسب را انجام خواهد داد.
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.BindingAdapter;
import androidx.databinding.DataBindingUtil;
import com.example.mvvmarchitecture.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ViewModel updates the Model
// after observing changes in the View
// model will also update the view
// via the ViewModel
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
activityMainBinding.setViewModel(new AppViewModel());
activityMainBinding.executePendingBindings();
}
// any change in toastMessage attribute
// defined on the Button with bind prefix
// invokes this method
@BindingAdapter({“toastMessage”})
public static void runMe( View view, String message) {
if (message != null)
Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
}
}
خروجی برنامه:
در این مرحله از آموزش MVVM در محیط اندروید استودیو از برنامه خروجی میگیریم که مطابق ویدیوی کوتاه زیر است.