کلاس ViewModel ساخته شده تا اطلاعات مربوط به UI رو از UI-controller (اکتیویتی یا فرگمنت)جدا کنه.
داستان از اینجا شروع میشه که وقتی گوشی میچرخه و عمودی یا افقی میشه , اکتیویتی recreate میشه یعنی اول کاملا با خاک یکسان و دوباره از صفر ساخته میشه. در نتیجه خیلی از اطلاعاتی توی اکتیویتی ساخته شده از بین میره, متغیر ها مقدار پیشفرضشون رو میگیرن و اگه مثلا لیستی از اسم کاربر ها ساخته باشید از بین میره.
راهکار اینه که اطلاعاتی که توی اکتیویتی استفاده میشه رو توی یک کلاس جدا تعریف کنیم. وقتی اکتیویتی recreate میشه اون اطلاعات از بین نمیره چون توی اکتیویتی نیست. ViewModel برای همین کار ساخته شده.
کلاس ViewModel برای نگهداری اطلاعات مربوط به UI طراحی شده. این کلاس میتونه از هر چیزی که منجر به recreate شدن میشه جون سالم به در ببرن.
اگه یادتون باشه onSaveInstanceState() هم همین کار رو میکنه ولی مشکلش اینه که برای ذخیره اطلاعات کوچیک ساخته شده و اگر نیاز به ذخیره مقدار زیادی از اطلاعات داشته باشید باید از ViewModel استفاده کنید.
اکتیویتی یا فرگمنت ها برای نشون دادن اطلاعات و پاسخ به کار هایی مثل کلیک کردن طراحی شده و بهتره نگهداری اطلاعات رو به جای بهتری بسپاریم. به این ترتیب هم اکتیویتی ما تمیزتر خواهد بود و هم تست کردن برنامه راحت تر انجام میشه چون میتونیم اون کلاس رو جداگانه تست کنیم.
ساخت view model:
ViewMidwl ها به طور خودکار از تغییر وضعیت دستگاه(عمودی به افقی و بالعکس) جون سالم به در میبره , در نتیجه به محض اینکه اکتیویتی دوباره ساخته شد اطلاعات در دسترس هستند.
فرض کنید میخواهید لیستی از کاربرها توی برنامه تون نمایش داده بشه. مطمعن بشید که مسوولیت نگه داری این لیست رو به جای اکتیویتی یا فرگمنت به ViewModel میسپارید. به این کد نگاه کنید:
public class MyViewModel extends ViewModel { private MutableLiveData<List<User>> users; public LiveData<List<User>> getUsers() { if (users == null) { users = new MutableLiveData<List<User>>(); loadUsers(); } return users; } private void loadUsers() { // Do an asynchronous operation to fetch users. } }
لیستی از کاربر ها رو در قالب LiveData نگه داشتیم. اگر با LiveData اشنایی ندارید این مقاله رو بخونید:
توی getUsers اون رو مقدار دهی کردیم و میتونیم توی اکتیویتی ازش استفاده کنیم. یک نکته مهم وجود داره:
هیچوقت از هیچ شی ای از view و context در این کلاس استفاده نکنید. چون اینها فانی هستند ولی ViewModel تا وقتی لازم باشه هست.ممکنه در لحظه ای ViewModel نیاز به دسترسی به view داشته باشه ولی وجود نداشته باشه. اگر نیاز به application Context داشتید , کلاستون به جای ViewModel از AndroidViewModel باید ارث بری کنه.
public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class); model.getUsers().observe(this, users -> { // update UI }); } }
معمولا بهترین جا برای ساخت شی ViewModel و استفاده از اون همین متد onCreate هست. وقتی اکتیویتی ای که این شی در اون ساخته شده برای همیشه از بین بره و onDestroy صدا زده بشه, متد onCleared روی ViewModel اجرا و اطلاعات اون پاک میشه. بد نیست نگاهی به چرخه حیات ViewModel بندازیم.
وقتی ViewModel ساخته میشه یه جورایی از lifecycle اکتیویتی ای در اون ساخته شده خبر داره و تا زمانی که اون اکتیویتی وجود داره , ViewModel هنوز فعاله. ولی وقتی اکتیویتی نابود شد , اون هم از بین میره.
قصه ما به سر رسید ولی اگه کلاغتون هنوز به خونه اش نرسیده حتما داکیومنت های ViewModel رو بخونید.