Saved State module for ViewModel (Views) Part of Android Jetpack.
مفاهیم و پیادهسازی Jetpack Compose
همانطور که در ذخیره کردن حالتهای میانای کاربر ذکر شد، اشیای ViewModel میتوانند تغییرات پیکربندی را مدیریت کنند، بنابراین لازم نیست نگران حالت در چرخشها یا موارد دیگر باشید. بااینحال، اگر لازم است مرگ پردازش آغازشده توسط سیستم را مدیریت کنید،
شاید بخواهید از SavedStateHandle API بهعنوان پشتیبان استفاده کنید.
حالت میانای کاربر معمولاً در اشیاء ViewModel ذخیره یا ارجاع داده میشود و نه
فعالیتها، بنابراین استفاده از onSaveInstanceState() به مقداری کد تکراری نیاز دارد که
مدول حالت ذخیرهشده میتواند آن را برای شما مدیریت کند.
هنگام استفاده از این ماژول، اشیاء ViewModel یک شیء SavedStateHandle را ازطریق سازنده آن دریافت میکنند. این شیء یک نقشه کلید-مقدار است که به شما امکان میدهد
اشیاء را در وضعیت ذخیرهشده بنویسید و بازیابی کنید. این مقادیر پساز توقف پردازش توسط سیستم باقی میمانند و ازطریق همان شیء دردسترس خواهند بود.
وضعیت ذخیرهشده به پشته تکلیف شما گره خورده است. اگر پشته تکلیف شما ازبین برود، وضعیت ذخیرهشده شما نیز ازبین میرود. این اتفاق ممکن است هنگام توقف اجباری برنامه، برداشتن برنامه از منو موارد اخیر، یا بازراهاندازی دستگاه رخ دهد. دراینصورت، پشته تکلیف ناپدید میشود و نمیتوانید اطلاعات را در حالت ذخیرهشده بازیابی کنید. در سناریوهای رد کردن وضعیت میانای کاربر، وضعیت ذخیرهشده بازیابی نمیشود. در سناریوهای راهاندازیشده توسط سیستم، بله.
راهاندازی
با شروع از Fragment 1.2.0 یا وابستگی متعدی آن
Activity 1.1.0، میتوانید SavedStateHandle را بهعنوان آرگومان سازنده
برای ViewModel خود بپذیرید.
کاتلین
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }
جاوا
public class SavedStateViewModel extends ViewModel { private SavedStateHandle state; public SavedStateViewModel(SavedStateHandle savedStateHandle) { state = savedStateHandle; } ... }
سپس میتوانید نمونهای از ViewModel خود را بدون هیچ پیکربندی اضافی بازیابی کنید. کارخانه پیشفرض ViewModel، SavedStateHandle مناسب را برای ViewModel شما فراهم میکند.
کاتلین
class MainFragment : Fragment() { val vm: SavedStateViewModel by viewModels() ... }
جاوا
class MainFragment extends Fragment { private SavedStateViewModel vm; public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { vm = new ViewModelProvider(this).get(SavedStateViewModel.class); ... } ... }
هنگام ارائه نمونه ViewModelProvider.Factory سفارشی، میتوانید
استفاده از SavedStateHandle را با گسترش دادن
AbstractSavedStateViewModelFactory فعال کنید.
کار کردن با SavedStateHandle
کلاس SavedStateHandle یک نقشه کلید-مقدار است که به شما امکان میدهد دادهها را ازطریق روشهای set() و get() در وضعیت ذخیرهشده بنویسید و بازیابی کنید.
بااستفاده از SavedStateHandle، مقدار پُرسمان درطول مرگ پردازش حفظ میشود
و مطمئن میشوید که کاربر همان مجموعه دادههای فیلترشده را قبل و بعداز
بازآفرینی میبیند، بدون اینکه فعالیت یا قطعه نیاز به ذخیره، بازیابی،
و ارسال دستی آن مقدار به ViewModel داشته باشد.
SavedStateHandle همچنین روشهای دیگری دارد که ممکن است هنگام تعامل با نقشه مقدار کلید انتظار داشته باشید:
contains(String key)- بررسی میکند که آیا مقداری برای کلید دادهشده وجود دارد یا نه.remove(String key)- مقدار کلید دادهشده را برمیدارد.keys()- همه کلیدهای موجود درSavedStateHandleرا برمیگرداند.
علاوهبراین، میتوانید مقادیر را از SavedStateHandle بااستفاده از
نگهدارنده دادههای دیدهشدنی بازیابی کنید. فهرست انواع پشتیبانیشده:
LiveData
مقادیر را از SavedStateHandle که در LiveData پیچیده شده است
بااستفاده از getLiveData() بازیابی کنید. وقتی مقدار کلید بهروز میشود،
LiveData مقدار جدید را دریافت میکند. اغلب، این مقدار بهدلیل تعاملات کاربر تنظیم میشود، مانند وارد کردن یک پُرسمان برای فیلتر کردن فهرستی از دادهها. سپس میتوان از این مقدار بهروزشده برای تبدیل LiveData استفاده کرد.
کاتلین
class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { val filteredData: LiveData<List<String>> = savedStateHandle.getLiveData<String>("query").switchMap { query -> repository.getFilteredData(query) } fun setQuery(query: String) { savedStateHandle["query"] = query } }
جاوا
public class SavedStateViewModel extends ViewModel { private SavedStateHandle savedStateHandle; public LiveData<List<String>> filteredData; public SavedStateViewModel(SavedStateHandle savedStateHandle) { this.savedStateHandle = savedStateHandle; LiveData<String> queryLiveData = savedStateHandle.getLiveData("query"); filteredData = Transformations.switchMap(queryLiveData, query -> { return repository.getFilteredData(query); }); } public void setQuery(String query) { savedStateHandle.set("query", query); } }
نوعهای پشتیبانیشده
دادههای نگهداریشده در SavedStateHandle بهعنوان Bundle ذخیره و بازیابی میشوند،
همراه با بقیه savedInstanceState برای فعالیت یا
تکه.
ذخیره کردن کلاسهای غیرقابلتجزیه
اگر کلاسی Parcelable یا Serializable را پیادهسازی نکند و نتوان آن را برای پیادهسازی یکی از این رابطها اصلاح کرد، امکان ذخیره مستقیم نمونهای از آن کلاس در SavedStateHandle وجود ندارد.
با شروع از Lifecycle 2.3.0-alpha03، SavedStateHandle به شما امکان میدهد
هر شیئی را با ارائه منطق خودتان برای ذخیره و بازیابی شیء بهعنوان
Bundle بااستفاده از روش setSavedStateProvider() ذخیره کنید.
SavedStateRegistry.SavedStateProvider میانایی است که یک روش saveState() را تعریف میکند که Bundle حاوی وضعیتی را که میخواهید ذخیره کنید برمیگرداند. وقتی SavedStateHandle آماده ذخیره کردن وضعیتش است،
saveState() را برای بازیابی Bundle از SavedStateProvider فراخوانی میکند و
Bundle را برای کلید مرتبط ذخیره میکند.
مثالی از برنامهای را درنظر بگیرید که ازطریق هدف ACTION_IMAGE_CAPTURE تصویری را از برنامه دوربین درخواست میکند و فایل موقتی را برای جایی که دوربین باید تصویر را ذخیره کند ارسال میکند. TempFileViewModel منطق ایجاد آن فایل موقت را کپسولهسازی میکند.
کاتلین
class TempFileViewModel : ViewModel() { private var tempFile: File? = null fun createOrGetTempFile(): File { return tempFile ?: File.createTempFile("temp", null).also { tempFile = it } } }
جاوا
class TempFileViewModel extends ViewModel { private File tempFile = null; public TempFileViewModel() { } @NonNull public File createOrGetTempFile() { if (tempFile == null) { tempFile = File.createTempFile("temp", null); } return tempFile; } }
برای اطمینان از اینکه اگر فرایند فعالیت متوقف شد و بعداً بازیابی شد، فایل موقت ازبین نرود، TempFileViewModel میتواند از SavedStateHandle برای حفظ دادههایش استفاده کند. برای اینکه به TempFileViewModel اجازه دهید دادههایش را ذخیره کند،
SavedStateProvider را پیادهسازی کنید و آن را بهعنوان ارائهدهنده در SavedStateHandle
ViewModel تنظیم کنید:
کاتلین
private fun File.saveTempFile() = bundleOf("path", absolutePath) class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { private var tempFile: File? = null init { savedStateHandle.setSavedStateProvider("temp_file") { // saveState() if (tempFile != null) { tempFile.saveTempFile() } else { Bundle() } } } fun createOrGetTempFile(): File { return tempFile ?: File.createTempFile("temp", null).also { tempFile = it } } }
جاوا
class TempFileViewModel extends ViewModel { private File tempFile = null; public TempFileViewModel(SavedStateHandle savedStateHandle) { savedStateHandle.setSavedStateProvider("temp_file", new TempFileSavedStateProvider()); } @NonNull public File createOrGetTempFile() { if (tempFile == null) { tempFile = File.createTempFile("temp", null); } return tempFile; } private class TempFileSavedStateProvider implements SavedStateRegistry.SavedStateProvider { @NonNull @Override public Bundle saveState() { Bundle bundle = new Bundle(); if (tempFile != null) { bundle.putString("path", tempFile.getAbsolutePath()); } return bundle; } } }
برای بازیابی دادههای File هنگام بازگشت کاربر، temp_file
Bundle را از SavedStateHandle بازیابی کنید. این همان Bundle ارائهشده توسط
saveTempFile() است که حاوی مسیر مطلق است. سپس میتوان از مسیر مطلق برای نمونهسازی File جدید استفاده کرد.
کاتلین
private fun File.saveTempFile() = bundleOf("path", absolutePath) private fun Bundle.restoreTempFile() = if (containsKey("path")) { File(getString("path")) } else { null } class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { private var tempFile: File? = null init { val tempFileBundle = savedStateHandle.get<Bundle>("temp_file") if (tempFileBundle != null) { tempFile = tempFileBundle.restoreTempFile() } savedStateHandle.setSavedStateProvider("temp_file") { // saveState() if (tempFile != null) { tempFile.saveTempFile() } else { Bundle() } } } fun createOrGetTempFile(): File { return tempFile ?: File.createTempFile("temp", null).also { tempFile = it } } }
جاوا
class TempFileViewModel extends ViewModel { private File tempFile = null; public TempFileViewModel(SavedStateHandle savedStateHandle) { Bundle tempFileBundle = savedStateHandle.get("temp_file"); if (tempFileBundle != null) { tempFile = TempFileSavedStateProvider.restoreTempFile(tempFileBundle); } savedStateHandle.setSavedStateProvider("temp_file", new TempFileSavedStateProvider()); } @NonNull public File createOrGetTempFile() { if (tempFile == null) { tempFile = File.createTempFile("temp", null); } return tempFile; } private class TempFileSavedStateProvider implements SavedStateRegistry.SavedStateProvider { @NonNull @Override public Bundle saveState() { Bundle bundle = new Bundle(); if (tempFile != null) { bundle.putString("path", tempFile.getAbsolutePath()); } return bundle; } @Nullable private static File restoreTempFile(Bundle bundle) { if (bundle.containsKey("path") { return File(bundle.getString("path")); } return null; } } }
توصیهشده برای شما
- توجه: وقتی جاوا اسکریپت خاموش باشد، نوشتار پیوند نمایش داده میشود
- ذخیره کردن وضعیتهای میانای کاربر
- کار کردن با اشیای دادههای دیدهشدنی
- ایجاد ViewModels با وابستگیها