Fragment에서 onCreatView()가 호출될 때까지 레이아웃을 inflate할 수 없기 때문에 null을 허용해야 한다. null을 허용하기 때문에 null safety를 위해 ?
를 꼭 포함하자! 그리고 계속 ?을 쓰기는 번거롭기 때문에, ?을 쓰지 않고도 뷰를 참조할 수 있게 get-only 변수도 만들자.
// 변수 이름 앞에 _를 포함하면 이 변수에는 직접 액세스를 할 수 없다는 것을 의미한다
private var _binding: FragmentLetterListBinding? = null
// 아래와 같은 방법으로 binding 속성을 따로 사용해 액세스 하자
// 이때 get()은 이 변수가 read-only인 걸 나타낸다
// 때문에 값을 가져올 수는 있지만 다른 변수에 할당은 불가하다
private val binding get() = _binding!!
바인딩은 레이아웃이 inflate되는 onCreateView()에서 하고, 아래와 같이 활용한다.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentLetterListBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
메모리 누수를 막기 위해 onDetroyView()에서 다시 null로 설정해주는 것도 잊지 말자.
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
cf) Fragment 생명주기 중 CREATED 상태의 콜백들
cf) Fragment 생명주기 중 DESTROYED 상태의 콜백들
@SuppressLint("StaticFieldLeak")
MainActivity에서 다음과 같이 NavController를 만들었다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val navHostFragment =
supportFragmentManager.findFragmentById(binding.fragmentContainerView.id) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
그런데 navController를 Fragment에서 쓰려고 하니 아무래도 companion object에 NavController를 두는 게 좋겠다고 생각했다. 그런데 이렇게 노란 칠이 되면서 @SuppressLint("StaticFieldLeak")
이 뜨는 게 아닌가!
@SuppressLint("StaticFieldLeak")
이란?
설명에도 나와있듯이 memory leak, 메모리 누수를 일으킬 수 있다고 경고를 해두는 거다. 한 마디로 이렇게 쓰지 말라고, 나중에라도 꼬오오오오옥 수정하라고 표기를 시키는 거다. 좀 더 정확하게는 안드로이드를 정적 분석하고, 그래서 코드의 품질을 향상시키기 위해 사용하는 Android Lint가 경고하는 거라 볼 수 있다.
그렇다면 메모리 누수를 막으면서 Fragment에서 어떻게 NavController를 사용할까?
binding.floatingActionButton.setOnClickListener {
// NavController가 addFragment로 이동시킴
findNavController().navigate(R.id.action_listFragment_to_addFragment)
}
아주 간단하다. 위 코드처럼 findNavController()를 사용하면 된다.
이 프로그램을 활용하면 안드로이드에 저장된 DB를 내 컴퓨터에서 확인할 수 있다.
우선 Device File Explorer에서 다음과 같은 경로로 들어가 내 프로젝트를 찾아간다.
그러면 이렇게 세 가지의 파일이 나오는데 다 로컬에 저장하도록 하자.
그리고 프로그램을 켜서 데이터베이스 열기를 선택하고 모든 파일로 검색을 하는데, 내 테이블 이름만 있는 파일을 연다.
그렴 이렇게 데이터베이스 구조를 편하게 볼 수 있고,
데이터 확인도 가능하다!
Adapter의 메서드다. Adapter에게 데이터가 변경되었으니 모든 뷰는 자체적으로 새로 고쳐야 한다고 알려준다. 그러니까 아이템의 삽입, 삭제, 이동 등이 일어났을 때 사용한다. 아래와 같이.
// ListAdapter.kt
@SuppressLint("NotifyDataSetChanged")
fun setDate(user: List<User>) {
this.userList = user
notifyDataSetChanged()
}
// ListFragment.kt
mUserViewModler = ViewModelProvider(this)[UserViewModel::class.java]
mUserViewModler.readAllData.observe(viewLifecycleOwner, Observer {
// user -> 이렇게 바꾸는 게 훨씬 직관적인 코드지만 아직 헷갈리니까 자료형이 보이는 it으로 두자
// LiveData인 readAllData를 관찰하면서 바뀌는 걸 즉각적으로 반영함!
adapter.setDate(it)
})
cf) 다른 Adapter 메서드도 알아보자