- vừa được xem lúc

Tìm hiểu về SavedState cho ViewModel

0 0 2

Người đăng: Nguyen Manh Duc

Theo Viblo Asia

Giới thiệu

Tại sự kiện Google I/O 2018, Google giới thiệu về Android Jetpack, một bộ công cụ, thành phần và hướng dẫn để tạo ứng dụng Android xuất sắc hơn. Nó bao gồm các thành phần như LiveData, ViewModel, Room Database, Work Manager, và nhiều thành phần khác. Trong bài viết này chúng ta sẽ nói về ViewModel.

ViewModel quản lý dữ liệu liên quan đến giao diện người dùng trong vòng đời của Activity/Fragment. Nó cho phép dữ liệu tồn tại qua các thay đổi cấu hình trong ứng dụng (như xoay màn hình).

ViewModel thường được dùng để:

  1. Chuẩn bị dữ liệu cho tầng View
  2. Xử lý cấu hình khu ứng dụng xoay màn hình.

PS: Lớp ViewModel không nên chứa tham chiếu đến View (Activity/Fragment).

Vòng đời của ViewModel

ViewModel và onSaveInstanceState()

Triển khai ViewModel,

class MainViewModel : ViewModel() { val blogs = MutableLiveData<List<Blog>>() fun getBlogs(): LiveData<List<Blog>> { return blogs } private fun loadBlogs() { blogs.value = //our list of blogs }
}

và để lấy dữ liệu trên View,

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MainViewModel instance created by the first activity. val model = ViewModelProviders.of(this).get(MainViewModel::class.java) model.getBlogs().observe(this, Observer<List<Blog>>{ blogs -> // update UI }) }
}

Trong View (Activitys/Fragments), chúng ta phải kích hoạt ViewModel bằng cách sử dụng,

 val model = ViewModelProviders.of(this).get(MainViewModel::class.java)

và chúng ta có thể observe dữ liệu bằng,

model.getBlogs().observe(this, Observer<List<Blog>>{ blogs -> // update UI })

Đây là cách chúng ta sử dụng ViewModel trong View của mình.

Bây giờ, trong ViewModel, chúng ta chỉ có thể xử lý các thay đổi cấu hình trong View, nhưng nó không lưu trữ Trạng thái của UI hoặc View. Nhưng nó không xử lý Sự chết của quá trình được khởi tạo bởi hệ thống. Để xử lý điều này, chúng ta có thể sử dụng onSaveInstanceState() để khôi phục trạng thái chúng ta đã rời đi.

Sự chết của quá trình được khởi tạo bởi hệ thống có thể được định nghĩa như sau: Mỗi ứng dụng Android chạy trong process Linux riêng của nó. Process này được tạo ra cho ứng dụng khi một số mã của nó cần được thực thi và sẽ tiếp tục chạy cho đến khi không còn cần thiết nữa và hệ thống cần thu hồi bộ nhớ của nó để sử dụng cho các ứng dụng khác.

Nếu ứng dụng của bạn không ở trong trạng thái foreground, hệ thống có thể chấm dứt quá trình của bạn bất kỳ lúc nào để giải phóng bộ nhớ hệ thống để sử dụng cho các quá trình khác.

  • Phương thức onSaveInstanceState() và bundle có thể xử lý cả cấu hình và sự chết của quá trình được khởi tạo bởi hệ thống. Khi chúng ta mở lại ứng dụng và chuyển ứng dụng của chúng ta vào trạng thái foreground, chúng ta vẫn có thể thấy dữ liệu của mình được lưu trữ bằng onSaveInstanceState().
  • Nhưng nó chỉ có thể lưu trữ một lượng dữ liệu hạn chế và phụ thuộc rất nhiều vào tốc độ cũng như dung lượng lưu trữ vì việc Tuần tự hóa (Serialization) có thể tốn rất nhiều bộ nhớ để lưu trữ dữ liệu.
  • Quá trình tuần tự hóa xảy ra trên luồng chính nên trong khi thay đổi cấu hình, nó có thể chặn màn hình giao diện người dùng và cũng có thể khiến ứng dụng bị treo (ANR), tức là Ứng dụng không phản hồi.
  • Phương thức onSaveInstanceState() có thể lưu trữ một lượng dữ liệu tối thiểu và không phải là lượng lớn.

SavedState

Trong sự kiện Google I/O 2019, Google đã ra mắt SavedState cho ViewModel link

Saved State của ViewModel có thể được xem xét như một phương thức thay thế cho onSaveInstanceState(), vì nó cũng có thể lưu trữ dữ liệu. Bởi vì dữ liệu UI luôn được tham chiếu từ ViewModel của Architecture Components và không phải từ View (Activity/Fragment). Vì vậy, để sử dụng onSaveInstanceState(), chúng ta sẽ cần phải thực hiện một số code.

Vì vậy, với tư cách là một phần của Jetpack, Google đã ra mắt một thứ gọi là Saved State, giúp chúng ta lưu trữ và truy xuất dữ liệu từ trạng thái đã lưu sau khi nó trải qua System Initiated Process Death.

Triển khai

Để tích hợp Saved State trong dự án, thêm mã bên dưới vào build.gradle của project

implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha01'

cập nhật đoạn code bên dưới trong onCreate() của View (Activity/Fragment) của bạn,

val model = ViewModelProviders.of(this, SavedStateVMFactory(this)).get(MainViewModel::class.java)

thay cho,

val model = ViewModelProviders.of(this).get(MainViewModel::class.java)

và trong ViewModel,

class MainViewModel(private val state: SavedStateHandle) : ViewModel() { ... }

Ở đây, bạn có thể thấy chúng ta đã chuyển SavedStateHandle vào hàm tạo chính của ViewModel. Để có được SavedStateHandle, chúng ta truyền SavedStateVMFactory() vào ViewModelProviders.of như một Factory.

Factory là một Interface cho ViewModel biết cách tạo ViewModel.

Ở đây, SavedStateHandle là một bảng điều khiển nằm trong một cặp Key-Value, giúp bạn đọc và ghi đối tượng vào và từ trạng thái đã lưu. Dữ liệu vẫn sẽ được duy trì ngay cả khi ứng dụng trải qua sự chết của quá trình được khởi tạo bởi hệ thống.

  • SavedStateHandle giống như SharedPreferences trong Android, hoạt động dựa trên cặp Key-Value.

Ví dụ

  • Chúng ta sẽ xây dựng một ứng dụng với 3 thành phần giao diện người dùng (EditText, Button và TextView).
  • Khi người dùng nhập tên người dùng vào EditText và nhấp vào nút, ứng dụng sẽ hiển thị tên người dùng trong TextView.

Đây là những gì chúng ta sẽ xây dựng, Bây giờ MainViewModel sẽ trông như thế này,

class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel(), BaseViewModel { override fun getUserName(): LiveData<String> { return savedStateHandle.getLiveData(Constants.USERNAME) } override fun saveUserName(username: String) { savedStateHandle.set(Constant.USERNAME, username) }
}
  • saveStateHandle.set("Key","Value") được sử dụng để lưu trữ dữ liệu
  • saveStateHandle.getLiveData("key") được sử dụng để trả về LiveData của kiểu dữ liệu String

BaseViewModel trông giống như sau và được triển khai bởi Lớp MainViewModel.

interface BaseViewModel { fun getUserName(): LiveData<String> fun saveUserName(username: String)
}

Và cuối cùng, tệp lớp MainActivity trông như sau,

class MainActivity : AppCompatActivity() { lateinit var mainViewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val factory = SavedStateVMFactory(this@MainActivity) mainViewModel = ViewModelProviders.of(this, factory).get(MainViewModel::class.java) setupActions() } private fun setupActions() { submitButton.setOnClickListener { mainViewModel.saveUserName(username_edittext.text.toString() } mainViewModel.getLiveDataUserName().observe(this, Observer { saved_textview.text= "LiveData Result: $it" }) }
}

Bây giờ, để kiểm tra SavedState, bạn cần có Emulator/Device OS ít nhất Android Pie (+). Chúng ta phải tuân theo trạng thái sau để mô phỏng System Initiate Process Death,

  • Chúng ta phải đảm bảo rằng Ứng dụng hiện đang chạy trên Thiết bị Android bằng cách
adb shell ps -A | grep lifecycle
  • Nó sẽ hiển thị Output có tên vòng đời Ứng dụng của bạn như " com.android.app " trong terminal của bạn
adb shell am kill your-app-package-name
  • Để xác nhận, bạn nên chạy lại Bước 1 và bạn sẽ không thấy tên gói ứng dụng của bạn trong cửa sổ terminal.
  • Bây giờ hãy mở lại ứng dụng và bạn sẽ thấy đầu ra được lưu và hiển thị trong TextView của màn hình.

Một số thứ cần lưu ý

  1. Nếu bạn muốn đặt dữ liệu trong savedState, sử dụng:
savedStateHandle.set("key_name","value")
  1. Nếu bạn muốn lấy dữ liệu từ savedState, sử dụng:
savedStateHandle.get("key_name")
  1. Nếu bạn muốn nhận LiveData như kiểu trả về, sử dụng:
savedStateHandle.getLiveData("key_name")
  1. Nếu bạn muốn kiểm tra xem khóa cụ thể có tồn tại trong savedState không, sử dụng:
savedState.contains("key_name")

và nó trả về kiểu dữ liệu boolean, khi đúng có nghĩa là savedState chứa giá trị và khi sai có nghĩa là không chứa.

  1. Nếu bạn muốn tìm tất cả các khóa trong savedState, sử dụng đoạn mã sau, nó sẽ trả về danh sách các khóa.
savedState.keys()
  1. Và để xóa bất kỳ giá trị cụ thể nào, bạn có thể truy cập nó thông qua khóa của nó để xóa nó. Để làm điều này, sử dụng:
savedState.remove("key_name")

Kết luận

Cảm ơn bạn đã đọc tới đây, hi vọng thông qua bài viết này bạn đã nắm được về SaveState của ViewModel và có thể ứng dụng nó thành công trong dự án Android của bạn. Thanks!

Nguồn tham khảo: https://blog.mindorks.com/viewmodel-with-savedstate/

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 1: Làm quen cô nàng Flutter

Lời mở đầu. Gần đây, Flutter nổi lên và được Google PR như một xu thế của lập trình di động vậy.

0 0 254

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 3: Lột trần cô nàng Flutter, BuildContext là gì?

Lời mở đầu. Màn làm quen cô nàng FLutter ở Phần 1 đã gieo rắc vào đầu chúng ta quá nhiều điều bí ẩn về nàng Flutter.

0 0 189

- vừa được xem lúc

[Android] Hiển thị Activity trên màn hình khóa - Show Activity over lock screen

Xin chào các bạn, Hôm nay là 30 tết rồi, ngồi ngắm trời chờ đón giao thừa, trong lúc rảnh rỗi mình quyết định ngồi viết bài sau 1 thời gian vắng bóng. .

0 0 93

- vừa được xem lúc

Tìm hiểu Proguard trong Android

1. Proguard là gì . Cụ thể nó giúp ứng dụng của chúng ta:. .

0 0 83

- vừa được xem lúc

Làm ứng dụng học toán đơn giản với React Native - Phần 6

Chào các bạn một năm mới an khang thịnh vượng, dồi dào sức khỏe. Lại là mình đây Đây là link app mà các bạn đang theo dõi :3 https://play.google.com/store/apps/details?id=com.

0 0 51

- vừa được xem lúc

20 Plugin hữu ích cho Android Studio

1. CodeGlance. Plugin này sẽ nhúng một minimap vào editor cùng với thanh cuộn cũng khá là lớn. Nó sẽ giúp chúng ta xem trước bộ khung của code và cho phép điều hướng đến đoạn code mà ta mong muốn một cách nhanh chóng.

0 0 301