Android/LiveData
${Harvey}
2022. 11. 22. 17:47
2022. 11. 22. 17:47
val testDataList : List<String> = listOf(
"apple",
"strawberry",
"pineapple",
"peach",
"grape",
"melon",
"mango",
)
class MainViewModel : ViewModel() {
private var _mutableWord = MutableLiveData(" ")
val liveWord : LiveData<String>
get() = _mutableWord
private var _randomMutableWord = MutableLiveData(" ")
val randomLiveWord : LiveData<String>
get() = _randomMutableWord
val newData = Transformations.switchMap(liveWord){
getRandomWordShuffled(it )
}
init {
getNextData()
//초기값 초기화
}
fun getNextData(){
val currentWord = testDataList.random()
val randomWord = currentWord.toCharArray()
randomWord.shuffle()
_mutableWord.value = currentWord
_randomMutableWord.value = String(randomWord)
}
fun getRandomWordShuffled(word : String) : MutableLiveData<String>{
val liveData = MutableLiveData(" ")
val randomTextWord = word.toCharArray()
randomTextWord.shuffle()
liveData.value = String(randomTextWord)
return liveData
}
}
class MainViewModel : ViewModel() {
private var _mutableWord = MutableLiveData(" ")
val liveWord : LiveData<String>
get() = _mutableWord
private var _randomMutableWord = MutableLiveData(" ")
val randomLiveWord : LiveData<String>
get() = _randomMutableWord
val newData = Transformations.switchMap(liveWord){
getRandomWordShuffled(it)
}
init {
getNextData()
}
fun getNextData(){
val currentWord = testDataList.random()
val randomWord = currentWord.toCharArray()
randomWord.shuffle()
_mutableWord.value = currentWord
_randomMutableWord.value = String(randomWord)
}
fun getRandomWordShuffled(word : String) : MutableLiveData<String>{
val liveData = MutableLiveData(" ")
val randomTextWord = word.toCharArray()
randomTextWord.shuffle()
liveData.value = String(randomTextWord)
return liveData
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="vm"
type="com.example.livedata5.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:text="@{vm.liveWord}"
android:textSize="50sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{vm.randomLiveWord}"
android:textSize="50sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{vm.newData}"
android:textSize="50sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/next"
android:text="next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
${Harvey}
2022. 11. 22. 17:46
2022. 11. 22. 17:46
LiveData는 Map 또는 SwitchMap으로 데이터를 변환시킬 수 있다.
MainActivity.kt
// LiveData Transformations
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.liveCount.observe(this, Observer {
// binding.resultArea1.text = (it + it).toString()
// binding.resultArea2.text = (it * it).toString()
})
viewModel.mapLiveData.observe(this, Observer {
binding.resultArea1.text = it.toString()
})
viewModel.switchMapLiveData.observe(this, Observer {
binding.resultArea2.text = it.toString()
})
binding.btnArea.setOnClickListener {
val count = binding.inputArea.text.toString().toInt()
viewModel.setLiveDataValue(count)
}
}
}
class MainViewModel : ViewModel() {
// Transformations -> map / switchMap
// map -> 값을 return
private var _mutableCount = MutableLiveData(0)
val liveCount : LiveData<Int>
get() = _mutableCount
val mapLiveData = Transformations.map(liveCount) {
it+it
}
val switchMapLiveData = Transformations.switchMap(liveCount) {
changeValue(it)
}
fun setLiveDataValue(count : Int) {
_mutableCount.value = count
}
fun changeValue(count : Int) : MutableLiveData<Int> {
val testLiveData = MutableLiveData(count*count)
return testLiveData
}
}
Map과 SwitchMap의 차이가 뭔지 찾아보았다.
1.리턴 타입의 차이가 있다.
map 은 map() 내부에서 LiveData<X>의 객체를 반환한다. 데이터 변환 처리함수에서 X를 반환.
switchMap()은 데이터 변환을 처리하는 함수에서 LiveData<X>를 반환한다.
2.map()과 switchMap() 을 일대일 정적 변환 , 일대일 동적 변환이라 표현도 한다.
3.주로 시간이 오래 안걸리는 작업은 map s()에서, 오래 걸리는 작업은 switchMap()에서 한다.
${Harvey}
2022. 11. 22. 17:45
2022. 11. 22. 17:45
// Fragment LiveData / viewLifecyclerOwner
// https://developer.android.google.cn/codelabs/kotlin-android-training-live-data/index.html?index=..%2F..android-kotlin-fundamentals&hl=IT#4
// https://developer.android.com/topic/libraries/view-binding
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
val manager = supportFragmentManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.btn1.setOnClickListener {
val transaction1 = manager.beginTransaction()
val fragment1 = BlankFragment1()
transaction1.replace(R.id.frameArea, fragment1)
transaction1.addToBackStack(null)
transaction1.commit()
}
class BlankViewModel1 : ViewModel() {
private var _mutableCount = MutableLiveData(0)
val liveCount : LiveData<Int>
get() = _mutableCount
fun plusCountValue(){
_mutableCount.value = _mutableCount.value?.plus(1)
}
}
class BlankFragment1 : Fragment() {
// ViewBinding + LiveData
private val TAG = "BlankFragment1"
private var _binding : FragmentBlank1Binding? = null
private val binding get() = _binding!!
private lateinit var viewModel: BlankViewModel1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
// Inflate the layout for this fragment
_binding = FragmentBlank1Binding.inflate(inflater, container, false)
val view = binding.root
viewModel = ViewModelProvider(this).get(BlankViewModel1::class.java)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btn1.setOnClickListener {
viewModel.plusCountValue()
}
viewModel.liveCount.observe(viewLifecycleOwner, Observer {
binding.text1.text = it.toString()
})
}
override fun onDestroyView() {
super.onDestroyView()
Log.d(TAG, "onDestroyView")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
}
}
Fragment에선 생명주기가 달라 생길 수 있는 오류들을 해결하기위해 viewLifecycleOwner를 사용해야한다.
BlankFragment2.kt
class BlankFragment2 : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank2, container, false)
}
}
${Harvey}
2022. 11. 22. 17:44
2022. 11. 22. 17:44
MutableLiveData와 달리 LiveData는 외부에서 접근이 불가능하다.
MainViewModel.kt
class MainViewModel : ViewModel(){
private var _testMutableLiveData = MutableLiveData(0)
val testLiveData : LiveData<Int>
get() = _testMutableLiveData
fun plusLiveDataValue(){
_testMutableLiveData.value = _testMutableLiveData.value!!.plus(1)
}
// var testMutableLiveData = MutableLiveData(0)
//
// //MutableLiveData <-> LiveData
//
// fun plusLiveDataValue(){
// testMutableLiveData.value = testMutableLiveData.value!!.plus(1)
// }
}
class MainActivity : AppCompatActivity() {
private lateinit var viewModel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
findViewById<Button>(R.id.btnArea).setOnClickListener {
viewModel.plusLiveDataValue()
}
viewModel.testLiveData.observe(this,Observer{
findViewById<TextView>(R.id.textArea).text = it.toString()
})
viewModel.testLiveData = 10 //오류가 나는 부분.
// findViewById<Button>(R.id.btnArea).setOnClickListener {
// viewModel.plusLiveDataValue()
// }
//
//
// viewModel.testMutableLiveData.observe(this, Observer{
//// findViewById<TextView>(R.id.textArea).text = viewModel.testMutableLiveData.value.toString()
// findViewById<TextView>(R.id.textArea).text = it.toString() //위 코드와 동일.
//
//
// })
//
// viewModel.testMutableLiveData.value=10
}
}
위와 같이 ViewModel내의 LiveData에는 접근하지 못한다. -> ViewModel 내부에서만 로직 작성 가능.
${Harvey}
2022. 11. 22. 01:17
2022. 11. 22. 01:17
class MainActivity : AppCompatActivity() {
private lateinit var viewModel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
findViewById<Button>(R.id.btnArea).setOnClickListener {
viewModel.plusLiveDataValue()
}
viewModel.testMutableLiveData.observe(this, Observer {
findViewById<TextView>(R.id.textArea).text = viewModel.testMutableLiveData.value.toString()
})
}
}
class MainViewModel : ViewModel() {
var testMutableLiveData = MutableLiveData(0)
// MutableLiveData <-> LiveData
fun plusLiveDataValue(){
testMutableLiveData.value = testMutableLiveData.value!!.plus(1)
}
}
ViewModel을 통해 생명주기에서 데이터를 유지할수 있음.
${Harvey}
2022. 11. 21. 22:44
2022. 11. 21. 22:44
LiveData : 데이터를 관찰해줄 수 있는 친구.
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var testMutableLiveData = MutableLiveData(0)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.btnArea).setOnClickListener {
testMutableLiveData.value = testMutableLiveData.value!!.plus(1)
}
testMutableLiveData.observe(this, Observer{
Log.d("testMutableLiveData",testMutableLiveData.value.toString())
findViewById<TextView>(R.id.textArea).text = testMutableLiveData.value.toString()
})
}
}