آموزش معماری MVVM در اندروید
امروز استفاده و پیاده سازی معماری های برنامه نویسی جزو اولویت های برنامه نویسان حرفه ای میباشد از همین رو در چندین سال گذشته معماری هایی مانند MVC , MVP , معماری MVVM و Clean architecture وارد توسعه اپلیکیشن های اندروید شده اند.از همین رو برای اینکه اپلیکیشنی قوی , گسترش پذیر و قابل تست داشته باشیم میبایستی معماری مناسبی برای اپلیکیشن پیاده سازی کنیم.
انواع معماری های برنامه نویسی در اندروید
(MVVM (Model, View, View Model
(MVP (Model, View, Presenter
(MVC (Model, View, Controller
آشنایی با معماری MVVM در اندروید
معماری MVVM یک الگوی معماری سه لایه بر پایه Model – View – ViewModel هست . شرکت گوگل به این معماری دل ( عشق ) ورزیده و کامپوننت هایی تحت عنوان android.arch برای آن منتشر کرده است .
مزیت های استفاده از معماری MVVM
- اجزای UI بطور کامل از منطق برنامه جدا هستند.
- منطق برنامه از عملیات دیتابیسی جدا هستند.
- خوانایی و فهم کد بسیار ساده تر می شود.
- مدیریت life cycle events کمتر برعهده برنامه نویس است. مثلا وقتی کاربر در حالت (state) مشخصی از برنامه خارج می شود و چند ساعت بعد دوباره برمی گردد، برنامه در همان حالتی است که کاربر آنرا ترک نموده است. به عبارت بهتر راه حل جایگزین استفاده از onSaveInstanceState است.
معماری MVVM چیست ؟
MVVM مخفف Model، View، ViewModel میباشد.
Model، View، ViewModel یک الگوی معماری برنامه است که توسط جان گاسمن که به عنوان جایگزینی برای الگوهای MVC و MVP هنگام استفاده از Data Binding پیشنهاد شده است. MVVM یک الگوی طراحی معماری نرم افزار است که جداسازی رابط کاربری از business logic و مدل داده (Data model) برنامه را بهبود می دهد.
مدل (Model)
لایه مدل می تواند شامل دسترسی به داده ها , دیتابیس , مدل ها و Repository ها باشد .مدل یه لایه ارائه دهنده و بروز رسانی اطلاعات است .
دادهها را میتوان از منابع مختلف بازیابی کرد، به عنوان مثال:
- RestFull API
- SQLite db
- Handles broadcast
- Shared Preferences
- Firebase
Model از View یا ViewModel اطلاعی ندارد و به طور مستقل کار میکند. اگر یک برنامهی که قبلاً بر اساس الگوی MVC یا MVP ساخته شده است، به MVVM منتقل کنید ، لایهی Model به احتمال زیاد نیازی به تغییر نخواهد داشت چون وابسته به لایه های دیگر نبوده و براحتی قابل انتقال می باشد.
ویو (View)
ویو همان صفحه ای است که کاربر آن را می بیند(UI) که در اپلیکیشن های اندروید XML میباشد که در اکتیویتی و فرگمنت قابل استفاده می باشند.در معماری MVVM لایه View و مدل ارتباطی با هم ندارند و View با ViewModel در ارتباط است.
در View میتوان کارهای زیر را انجام داد:
- نمایش منو ها Menu
- مجوز ها Permissions
- رویداد ها Event Listener
- نمایش دیالوگ ها
- نمایش Toast و SnackBar
- Working with Android View and Widget
- Start Activities
- و تمام کارهای مرتبط با Context
ویو مدل (ViewModel)
ViewModel شما اطلاعاتی است که View به آنها نیاز دارد.همانطور که از نام آن مشخص است ٰViewModel پل ارتباطی ما بین View و Model است. روال کار به این صورت است که مدل دیتا ها را واکشی میکند و در اختیار ViewModel قرار می دهد و سپس ViewModel آن را در View نمایش می دهد. کلاس های ViewModel بصورت POJO هستند که میتوانند بطور مستقل نیز اجرا شوند و قابل تست هستند
از جمله مزایای ViewModel می توان به موارد زیر اشاره کرد :
- استفاده مجدد از کد (Code reuse)
- تست نویسی آسان
- Bind کردن دیتاها به UI
- قابلیت نگه داری آسان
وظایف ViewModel :
- نمایش اطلاعات
- منتشر کردن وضعیت دیتاها مانند ProgressBar , نمایش خطاها و …
- مدیریت نمایش/مخفی نمودن کنترل ها
- مدیریت Validation کنترل ها
- اجرای متدهای Model
- نمایش اطلاعات خروحی Model در View
ViewModel ها فقط باید دربارهی Context اطلاعات داشته باشد. Context میتواند شامل موارد زیر باشند :
- اجرای اکتیویتی جدید start Activity
- Bind کردن سرویس ها
- ارسال سرویس های Broadcast
- Register کردن سرویس های Broadcast
- استفاده از منابع Resource
کارهایی که نباید در ViewModel انجام داد شامل موارد زیر است :
- نمایش دیالوگ ها Dialog
- Start کردن اکتیویتی ها
- inflate کردن لایوت ها برای View ها
تفاوت MVVM با MVP:
- لایه ViewModel بجای لایه Presenter در لایه میانی است.
- Presenter متصل به View است اما ViewModel متصل به View نیست.
- Presenter و View رابطه 1 به 1 دارند.
- ViewModel اطلاعی ندارد که View در حال گوش دادن به آن است.
دو مدل پیاده سازی معماری MVVM در اندروید :
- DataBinding
- RxJava
Data Binding در اندروید از جمله کتابخانه های مشهور در JetPack اندروید میباشد که به منظور اتصال دادن داده ها بطور مستقیم در Xml Layout است. حتما پیشنهاد میشود قبل از اینکه معماری MVVM را شروع کنید با کتابخانه DataBinding آشنا شوید.
مثال : ما در این مثال قصد داریم یک صفحه ورود کاربران را پیاده سازی کنیم و در صورتی که کاربر اطلاعات را وارد نکرد و یا اینکه ایمیل معتبر را وارد نکرد با پیغام ها مواجه شود و در صورت درست بودن اطلاعات پیغام خوش آمد گویی نمایش داده می شود
چگونه ممکن است به برخی از کلاس ها بدون داشتن مرجع از آن اطلاع داده شود؟
- با استفاده از Two Way Data Binding
- با استفاده از LiveData
- با استفاده از RxJava
از جمله موارد مهم قابل اشاره این است که دیگر نیازی به استفاده از interface و یا کتابخانه هایی مانند EventBus نیست و LiveData اینکار را برعهده می گیرد.
پیاده سازی روش Two Way Data Binding :
اتصال دو طرفه داده ها روشی است برای اتصال object های شما به لایوت های XML . به گونه ای که Object و Layout می توانند داده ها را به یکدیگر ارسال کنند.
در مثال ما ، ViewModel می تواند داده ها را به لایوت ها ارسال کند و همچنین تغییرات را مشاهده (Listen) کند. برای اینکار نیاز داریم که با خصوصیت Binding Adapter استفاده کنیم تا بتوانیم در xml Layout ها این پیاده سازی را انحام دهیم.
ساختار پروژه براساس معماری MVVM :
ابتدا کتابخانه Data Biding را فعال نمایید
buildFeatures {
dataBinding true
}
این فعال سازی باعث می شود Data Binding در اپلیکیشن فعال شود
افزودن کتابخانه:
میبایستی در فایل build.gradle app در بخش Dependencies کتابخانه زیر را قرار دهید :
implementation 'android.arch.lifecycle:extensions:1.1.0'
مدل (Model)
مدل ایمیل و رمز عبور کاربر را نگه میدارد. کلاس User.java این کار را انجام میدهد:
package com.journaldev.androidmvvmbasics.model;
public class User {
private String email;
private String password;
public User(String email, String password) {
this.email = email;
this.password = password;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
}
Two Way Data Binding به ما اجازه را میدهد تا اشیاء را در Layout اتصال بدهیم به شکلی که Object ها بتواند دادهها را به Layout بفرستند و بالعکس.
{Syntax For Two Way Data Binding @={variable
Layout
کد مربوط به لایوت activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:bind="https://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.journaldev.androidmvvmbasics.viewmodels.LoginViewModel" />
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:orientation="vertical">
<EditText
android:id="@+id/inEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Email"
android:inputType="textEmailAddress"
android:padding="8dp"
android:text="@={viewModel.userEmail}" />
<EditText
android:id="@+id/inPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
android:inputType="textPassword"
android:padding="8dp"
android:text="@={viewModel.userPassword}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:onClick="@{()-> viewModel.onLoginClicked()}"
android:text="LOGIN"
bind:toastMessage="@{viewModel.toastMessage}" />
</LinearLayout>
</ScrollView>
</layout>
در اینجا ViewModel دادهها را به View متصل میکند. ()viewModel.onLoginClicked<-() این دکمه به صورت lambda در ViewModel تعریف و فراخوانی میشود.
EditText مقادیر موجود در مدل را از طریق View Model به روز می کند.
{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 تعریف کنیم.
در داخل تنظیم کننده ، ما به مشاهده کننده (که در برنامه ما View خواهد بود) اطلاع می دهیم که داده ها تغییر کرده اند. View (اکتیویتی) می تواند اقدامات(action) مناسب را انجام دهد.
کد کلاس MainActivity.java
import android.databinding.BindingAdapter;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.journaldev.androidmvvmbasics.R;
import com.journaldev.androidmvvmbasics.databinding.ActivityMainBinding;
import com.journaldev.androidmvvmbasics.viewmodels.LoginViewModel;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
activityMainBinding.setViewModel(new LoginViewModel());
activityMainBinding.executePendingBindings();
}
@BindingAdapter({"toastMessage"})
public static void runMe(View view, String message) {
if (message != null)
Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
}
}
با تشکر از DataBinding ، کلاس ActivityMainBinding از Layout به صورت خودکار تولید می شود.هر زمان که ویژگی toastMessage تعریف شده روی دکمه تغییر کرد ، روشBindingAdapter فعال می شود.این باید از همان ویژگی تعریف شده در XML و در ViewModel استفاده کند.
بنابراین در برنامه فوق ، ViewModel با گوش دادن به تغییرات در View ، مدل را به روز می کند. همچنین ، مدل می تواند از طریق ViewModel با استفاده از notifyPropertyChanged ویو را به روز کند.
خروجی برنامه فوق به شکل زیر میباشد:
استفاده از معماری MVVM
دیدگاهتان را بنویسید