ViewModel Overview
ViewModel
class is designed to store and manage UI-related data in a lifecycle conscious way.:) ViewModel 클래스는 라이프사이클이 알고 있는 방법 안에서 UI 관련 데이터의 저장과 관리를 위해 디자인되었습니다.
The
ViewModel
class allows data to survive configuration changes such as screen rotations.The Android framework manages the lifecycles of UI controllers, such as activities and fragments.
:) 안드로이드 프레임워크는 액티비티와 프래그먼트 등의 UI 컨트롤러의 라이프사이클을 관리합니다.
The framework may decide to destroy or re-create a UI controller in response to certain user actions or device events that are completely out of your control.
:) 프레임워크는 어떤 사용자의 동작이나 제어에서 완전히 벗어난 장치 이벤트의 응답으로 UI 컨트롤러를 파괴하거나 다시 만들기 위한 결정을 할 지도 모릅니다.
If the system destroys or re-creates a UI controller, any transient UI-related data you store in them is lost.
:) 만약 시스템이 UI 컨트롤러를 파괴하거나 다시 만든다면, 시스템의 저장소가 어떤 일시적인 UI 관련 데이터를 잃어버립니다.
For example, your app may include a list of users in one of its activities.
:) 예를 들어, 당신의 앱에서의 활동 중의 하나에 사용자의 목록이 포함되어 있을 수 있습니다.
When the activity is re-created for a configuration change, the new activity has to re-fetch the list of users.
:) 액티비티가 구성 변경을 위해 다시 생성될 때, 새로운 액티비티는 사용자의 목록을 다시 가지고 와야 합니다.
For simple data, the activity can use the onSaveInstanceState()
method and restore its data from the bundle in onCreate()
,
:) 단순한 데이터의 경우, 액티비티는 onSaveInstanceState() 메서드를 사용하고 onCreate()의 bundle로부터 데이터를 회복할 수 있습니다.
but this approach is only suitable for small amounts of data that can be serialized then deserialized, not for potentially large amounts of data like a list of users or bitmaps.
:) 하지만 이 접근법은 직렬화 그 뒤에 역직렬화할 수 있는 단지 작은 데이터의 양을 위해 적합하며, 잠재적으로는 사용자의 목록이나 비트맵 같은 많은 데이터의 양에는 적합하지 않습니다.
Another problem is that UI controllers frequently need to make asynchronous calls that may take some time to return.
:) 또 다른 문제는 UI 컨트롤러가 자주 비동기 호출을 만들어서 반환하는데 시간이 걸릴 수 있다는 것입니다.
The UI controller needs to manage these calls and ensure the system cleans them up after it's destroyed to avoid potential memory leaks.
:) UI 컨트롤러는 이것들의 호출을 관리하고 잠재적인 메모리 누수를 피하기 위해 시스템이 파괴된 후에 시스템을 깨끗이 확보할 필요가 있습니다.
This management requires a lot of maintenance, and in the case where the object is re-created for a configuration change, it's a waste of resources since the object may have to reissue calls it has already made.
:) 이 관리는 많은 보수가 필요하며, 그리고 객체는 구성 변경을 위해 다시 생성되는 경우에는 객체가 이미 만든 것을 가지고 호출하여 재발행해야 하기 때문에 리소스의 낭비가 있습니다.
UI controllers such as activities and fragments are primarily intended to display UI data, react to user actions, or handle operating system communication, such as permission requests.
:) 액티비티와 프래그먼트와 같은 UI 컨트롤러는 주로 UI 데이터를 표시하거나, 사용자의 활동에 작용하거나, 또는 권한 요청 같은 운영 체제 통신을 다루기 위해 의도된 것입니다.
Requiring UI controllers to also be responsible for loading data from a database or network adds bloat to the class.
:) UI 컨트롤러가 데이터베이스나 네트워크에 데이터 로딩을 위해 책임을 요구하는 것은 클래스에 부풀림을 추가합니다.
Assigning excessive responsibility to UI controllers can result in a single class that tries to handle all of an app's work by itself, instead of delegating work to other classes.
:) UI 컨트롤러에게 과도한 책임을 할당하면 다른 클래스에 작업을 위임하는 대신에 앱의 작업 모두를 처리하려는 단일 클래스가 생길 수 있습니다.
Assigning excessive responsibility to the UI controllers in this way also makes testing a lot harder.
:) 이런 방식으로 UI 컨트롤러에게 과도한 책임을 할당하면 테스트가 더 많이 어려워집니다.
It's easier and more efficient to separate out view data ownership from UI controller logic.
:) 그것은 UI 컨트롤러 로직으로부터 뷰 데이터 소유권을 분리하는 것이 더 쉽고 효율적입니다.
Implement a ViewModel
Architecture Components provides ViewModel
helper class for the UI controller that is responsible for preparing data for the UI.
:) 컴퓨터 설계 방식 구성요소는 UI를 위한 데이터 준비를 담당하는 UI 컨트롤러를 위해 ViewModel 도우미 클래스를 제공합니다.ViewModel
objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance.
:) ViewModel 객체는 구성 변경 중에 자동적으로 유지되므로 보유하고 있는 데이터를 다음 액티비티나 프래그먼트 인스턴스에 즉시 사용할 수 있습니다.
For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel
, instead of an activity or fragment, as illustrated by the following sample code:
:) 예를 들어, 만약 앱에서 사용자의 목록을 보여줄 필요가 있다면, 다음 샘플 코드에서 설명하는 것처럼, 액티비티와 프래그먼트 대신에, ViewModel에 사용자 목록을 획득하고 유지하기 위한 책임을 할당하십시오.
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
You can then access the list from an activity as follows:
:) 그때에 다음 액티비티로부터 목록에 접근할 수 있습니다.
class MyActivity : 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 MyViewModel instance created by the first activity.
val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
If the activity is re-created, it receives the same MyViewModel
instance that was created by the first activity.
:) 만약 액티비티가 재생성된다면, 첫번째 액티비티에 의해 생성된 인스턴스와 같은 MyViewModel를 받습니다.
When the owner activity is finished, the framework calls the ViewModel
objects's onCleared()
method so that it can clean up resources.
:) 소유자 액티비티가 끝났을 때, 프레임워크는 ViewModel 객체의 onCleared() 메서드를 호출하여 리소스를 정리할 수 있습니다.
ViewModel
objects are designed to outlive specific instantiations of views or LifecycleOwners
.
:) ViewModel 객체는 뷰 또는 LifecycleOwners의 특정한 인스턴스보다 오래 살도록 디자인되었습니다.
This design also means you can write tests to cover a ViewModel
more easily as it doesn't know about view and Lifecycle
objects.
:) 이 디자인은 또한 ViewModel이 뷰와 Lifecycle 객체에 관해 알지 못함으로서 더 쉽게 테스트 작성을 할 수 있다는 것을 의미합니다.ViewModel
objects can contain LifecycleObservers
, such as LiveData
objects.
:) ViewModel 객체는 LiveData 객체 같은 LifecycleObservers를 포함할 수 있습니다.
However ViewModel
objects must never observe changes to lifecycle-aware observables, such as LiveData
objects.
:) 하지만 ViewModel 객체는 더 이상 LiveData 객체와 같은 생명주기를 알고 있는 관찰가능한 변경에 대해 관찰해서는 안됩니다.
If the ViewModel
needs theApplication
context, for example to find a system service, it can extend the AndroidViewModel
class and have a constructor that receives the Application
in the constructor, since Application
class extends Context
.
:) 만약에 예를 들어 시스템 서비스를 찾기 위한 ViewModel이 Application 문맥에 필요하다면, Application 클래스가 Context를 상속하기 때문에, AndroidViewModel 클래스를 확장하고 생성자 안에서 Application을 받는 생성자를 가질 수 있습니다.
The lifecycle of a ViewModel
ViewModel
objects are scoped to the Lifecycle
passed to the ViewModelProvider
when getting the ViewModel
.
:) ViewModel 객체는 ViewModel을 가져올 때 ViewModelProvider로 전달되는 Lifecycle에 범위가 됩니다.
The ViewModel
remains in memory until the Lifecycle
it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.
:) ViewModel은 Lifecycle이 끝날 때까지 메모리에 남아있습니다: 액티비티의 경우는 finished 되었을 때, 프래그먼트의 경우는 detached 되었을 때.
Figure 1 illustrates the various lifecycle states of an activity as it undergoes a rotation and then is finished.
:) 그림 1은 회전 후 완료되는 액티비티의 다양한 라이프사이클 상태를 보여줍니다.
The illustration also shows the lifetime of the ViewModel
next to the associated activity lifecycle.
:) 또한 그림에는 액티비티 라이프사이클과 관련된 ViewModel의 수명을 보여줍니다.
This particular diagram illustrates the states of an activity.
:) 이 특정 다이어그램은 액티비티의 상태를 보여줍니다.
The same basic states apply to the lifecycle of a fragment.
:) 같은 동일한 상태가 프래그먼트의 라이프사이클에 적용됩니다.
You usually request a ViewModel
the first time the system calls an activity object's onCreate()
method.
:) 일반적으로 ViewModel은 액티비티 객체의 onCreate() 메서드를 처음 호출할 때 요청합니다.
The system may call onCreate()
several times throughout the life of an activity, such as when a device screen is rotated.
:) 시스템은 기기의 스크린이 회전했을 경우, 액티비티의 수명동안 내내 onCreate()를 몇번이나 호출할 지도 모릅니다.
TheViewModel
exists from when you first request a ViewModel
until the activity is finished and destroyed.
:) ViewModel은 액티비티가 끝나거나 파괴될 때까지 ViewModel을 처음 요청할 때부터 존재합니다.
Share data between fragments
It's very common that two or more fragments in an activity need to communicate with each other.
:) 액티비티 안에서 2개 또는 그 이상의 프래그먼트가 서로 통신이 필요한 것이 매우 일반적입니다.
Imagine a common case of master-detail fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item.
:) 사용자가 리스트로부터 아이템을 선택하는 프래그먼트와 선택된 아이템의 내용을 보여주는 다른 프래그먼트를 가지고 있는 master 프래그먼트와 detail 프래그먼트의 일반적인 경우를 상상해 보십시오.
This case is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together.
:) 이 경우 2개의 프래그먼트 모두 일부 인터페이스 설명을 정의해야하며 소유자 액티비티는 2개를 함께 바인딩해야하므로 결코 사소하지 않습니다.
In addition, both fragments must handle the scenario where the other fragment is not yet created or visible.
:) 또한 2개의 프래그먼트는 다른 프래그먼트가 아직 생성되거나 보이지 않는 시나리오를 처리해야합니다.
This common pain point can be addressed by using ViewModel
objects.
:) 이것의 공통된 문제점은 ViewModel 객체를 사용하여 해결할 수 있습니다.
These fragments can share a ViewModel
using their activity scope to handle this communication, as illustrated by the following sample code:
:) 이러한 프래그먼트는 다음 샘플 코드에 보여지는 것처럼 통신을 처리하기위해 액티비티 범위를 사용하여 ViewModel로 공유할 수 있습니다.
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
Notice that both fragments retrieve the activity that contains them.
:) 2개의 프래그먼트 모두 포함된 액티비티를 검색합니다.
That way, when the fragments each get theViewModelProvider
, they receive the same SharedViewModel
instance, which is scoped to this activity.
:) 그런 식으로 프래그먼트가 각각 ViewModelProvider를 얻을 때, 동일한 SharedViewModel 인스턴스를 받고 액티비티에 적용됩니다.
This approach offers the following benefits:
:) 이 접근 방식은 다음과 같은 이점을 제공합니다:
- The activity does not need to do anything, or know anything about this communication.
:) 액티비티는 아무것도 할 필요가 없으며, 이 통신에 대해 아무것도 알 필요가 없습니다. - Fragments don't need to know about each other besides the
SharedViewModel
contract.
:) 프래그먼트는 SharedViewModel 계약 외에도 서로에 대해 알 필요가 없습니다.
If one of the fragments disappears, the other one keeps working as usual.
:) 만약 프래그먼트 중의 하나가 사라지면, 다른 하나는 평소와 같이 계속 동작합니다. - Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one.
:) 각 프래그먼트는 자신의 라이프사이클을 가지고 있으며 다른 하나의 라이프사이클의 영향을 받지 않습니다.
If one fragment replaces the other one, the UI continues to work without any problems.
:) 만약 하나의 프래그먼트가 다른 하나로 대체되면 UI는 아무 문제없이 계속 작동합니다.
Replacing Loaders with ViewModel
Loader classes like CursorLoader
are frequently used to keep the data in an app's UI in sync with a database.
:) CursorLoader와 같은 로더 클래스는 데이터베이스와 동기화되어 앱의 UI에 데이터를 보관하는데 자주 사용됩니다.
You can use ViewModel
, with a few other classes, to replace the loader.
:) ViewModel은 몇 가지 다른 클래스와 함께 사용하여 로더를 대체할 수 있습니다.
Using a ViewModel
separates your UI controller from the data-loading operation, which means you have fewer strong references between classes.
:) ViewModel을 사용하면 UI 컨트롤러가 데이터로딩 작업에서 분리되므로 클래스 간의 강력한 참조가 줄어들게 됩니다.
In one common approach to using loaders, an app might use a CursorLoader
to observe the contents of a database.
:) 로더를 사용하는 한 가지 일반적인 접근 방식에서 앱은 데이터베이스의 내용을 관찰하기 위해 CursorLoader를 사용할 수 있습니다.
When a value in the database changes, the loader automatically triggers a reload of the data and updates the UI:
:) 데이터베이스의 값이 변경될 때, 로더가 자동적으로 데이터를 다시 로드하고 UI를 업데이트합니다.
Figure 2. Loading data with loaders
ViewModel
works with Room and LiveData to replace the loader.
:) ViewModel은 로더를 대체하기 위해 Room과 LiveData와 함께 작동합니다.
The ViewModel
ensures that the data survives a device configuration change.
:) ViewModel은 데이터가 장치 구성 변경사항을 유지하도록 보장합니다.
Room informs your LiveData
when the database changes, and the LiveData, in turn, updates your UI with the revised data.
:) Room은 데이터베이스가 변경될 때 LiveData에 알려주고 LiveData는 수정된 데이터로 UI를 업데이트합니다.
Figure 3. Loading data with ViewModel
Additional resources
This blog post describes how to use a ViewModel
with a LiveData
to replace an AsyncTaskLoader
.
:) 이 블로그 게시물은 AsyncTaskLoader를 대체하기 위해 LiveData와 함께 ViewModel을 사용하는 방법을 설명합니다.
As your data grows more complex, you might choose to have a separate class just to load the data.
:) 데이터가 더 복잡해지면 데이터를 로드하기 위해 별도의 클래스를 선택하는 것이 좋을 수 있습니다.
The purpose ofViewModel
is to encapsulate the data for a UI controller to let the data survive configuration changes.
:) ViewModel의 목적은 UI 컨트롤러의 데이터를 캡슐화하여 데이터가 구성 변경사항을 유지할 수 있도록 하는 것입니다.
For information about how to load, persist, and manage data across configuration changes, see Saving UI States.
:) 구성 변경사항을 통해 데이터를 로드, 유지, 관리하는 방법에 대한 자세한 내용은 Saving UI States를 참조하십시오.
The Guide to Android App Architecture suggests building a repository class to handle these functions.
:) Guide to Android App Architecture는 이러한 기능을 처리하기 위해 저장소 클래스를 구축하는 것을 제안합니다.
ViewModel
is used in the Android Lifecycles codelab and the Sunflower demo app.
:) ViewModel은 안드로이드 라이프사이클 codelab과 Sunflower 데모 앱에 사용됩니다.
Also see the Architecture Components BasicSample .
:) 또한 Architecture Components BasicSample을 참조하십시오.
참고: https://developer.android.com/topic/libraries/architecture/viewmodel#kotlin
'프로그래밍 > Android' 카테고리의 다른 글
[Android] 이상한 안드로이드 권한 거부 (0) | 2021.06.03 |
---|---|
Android Gradle Sync Error (0) | 2019.04.16 |
MVC, MVP, MVVM 참고 사이트 (0) | 2017.06.26 |
Android Studio logcat color 설정하기 (0) | 2017.06.15 |
Android useful library (0) | 2016.09.05 |
댓글