제가 보려고 쓰는 글입니다. 설명이 부족할 수 있습니다.
implementation("androidx.fragment:fragment-ktx:1.4.1")
buildFeatures {
dataBinding true
}
build.gradle 추가.
1. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/frameArea"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Databinding 사용하기 위해 <layout> </layout> 으로 묶어줌
2. MainViewModel
class MainViewModel : ViewModel() {
private var num = 0
fun plus() {
num++
}
fun getNum() : Int{
return num
}
}
ViewModel 간단하게 생성
3. fragment_test.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/fragment_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="50sp"/>
<Button
android:id="@+id/plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="plus"/>
</LinearLayout>
</layout>
Databinding 사용하기 위해 으로 묶어줌
4. TestFragment
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [TestFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class TestFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
//JutoleS
private lateinit var binding : FragmentTestBinding //데이터바인딩
private val viewModel by viewModels<MainViewModel>() //ViewModel초기화
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
//JutoleS
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_test, container, false) //데이터바인딩
binding.run {
plus.setOnClickListener {
viewModel.plus() //Viewmodel사용
fragmentText.text = viewModel.getNum().toString()
}
}
return binding.root //리턴값설정
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment TestFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
TestFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
Fragment에서 ViewModel 초기화 하는법 private val 변수명 by viewModels<사용할뷰모델>()
5. MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
supportFragmentManager.commit {
replace(R.id.frameArea, TestFragment())
setReorderingAllowed(true)
addToBackStack("")
}
}
}
Databinding 사용, fragmentKTX 사용해서 Fragment 부착
*여기서 생기는 문제점
Fragment에서 ViewModel을 사용해도 화면회전과 같은 이벤트가 발생할 때
Fragment는 Activity에 붙어있기 때문에 ActivityLifeCycle의 영향을 받는다.
화면 회전을 하자 액티비티가 완전히 종료된다고 나온다.
그럼 Fragment는 Activity의 LifeCycle을 따르니깐 Activity가 종료될때 Fragment도 종료된다.
이때 ViewModel은 Fragment의 LifeCycle을 따른다. 그래서 ViewModel이 종료되는것이다.
그리고 Activity가 다시만들어지고 Fragment가 만들어지고 다시 새로운 ViewModel을 사용하는것이다.
그래서 Fragment에서만 ViewModel을 사용했을 경우엔 데이터가 온전히 저장되지않는다.
*해결방법
TestFragment의 private val viewModel by viewModels<MainViewModel>() 이부분을
by viewModels 대신 by activityViewModels로 바꾸면 된다.
아마 by viewModels는 해당뷰 (fragment)의 LifeCycle을 가지고,
by activityViewModels는 해당뷰(fragment)가 부착된 activity의 LifeCycle을 가지게 되는것같다.
'Android-Kotlin > JetPack' 카테고리의 다른 글
[Android] LiveData 란? (0) | 2022.06.25 |
---|---|
[Android] ViewModel 개념 (0) | 2022.06.24 |
[Android] DataBinding을 Fragment에서 사용하기 - Kotlin (0) | 2022.06.21 |
[Android] DataBinding 개념 및 간단 사용법 - Kotlin (0) | 2022.06.21 |