-
[Kotlin] 지연초기화(lateinit, by lazy), 위임(by)Kotlin 2024. 12. 20. 08:00728x90반응형
객체에 프로퍼티를 선언하면 초기화를 해주어야한다
근데 객체에 들어오는 정보가 나중에 오는 경우 지금 당장 초기화하기 어려울 수 있다
이런 경우 지연 초기화를 사용해 초기화를 지연시킨다
지연초기화를 할 때 latenit, by lazy라는 키워드를 사용해서 지연시킬 수 있다
이러한 키워드들을 사용해서 컴파일러한테 나중에 초기화를 하겠다고 알려주는 것이다
각각의 키워드들에 대해서는 아래에 정리하겠다!
1. lateinit
var로 선언한 프로퍼티에서 사용이 가능하고, 해당 프로퍼티에 getter, setter를 사용할 수 없다
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater).also { setContentView(it.root) } // ... 생략 }
MainActivity에서 binding이라는 프로퍼티를 lateinit을 통해 지연초기화하고 있다(참고로 뷰바인딩 사용)
그리고 액티비티가 생성될 때 onCreate()가 호출되고, 이 때 비로소 binding이 ActivityMainBinding으로 초기화되고 있다
이렇게 초기화되면 activity가 살아있는 동안 binding으로 xml 뷰를 참고하고 있는 객체에 바로 접근할 수 있다
ex : binding.tvTitle.setText("결과")
(val titleText = findViewById<EditText>(R.id.tvTitle) <- 계속 이렇게 일일히 view의 아이디를 찾아서 쓸 필요가 없다는 얘기임)
isInitialized api통해 초기화되었는지 아닌지를 확인할 수 있다
2. by lazy
최초로 호출된 시점에 해당 프로퍼티가 초기화가 된다
그리고 다시 호출할 때는 최초로 초기화된 값을 재사용함(읽기전용이므로 다시 값 재사용x)
즉, 호출한 시점에 by lazy{...} 에서 블록부분에 정의된 내용으로 초기화를 진행한다
val로 선언한 프로퍼티에서만 가능하다(읽기전용)
class RecentlyFoundNotesDetailFragment : BaseFragment<FragmentRecentlyFoundNotesDetailBinding>(FragmentRecentlyFoundNotesDetailBinding::inflate){ private val args : RecentlyFoundNotesDetailFragmentArgs by navArgs() private val noteDetail by lazy { args.recentlyFoundNoteDetail } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) with(binding){ toolbar.toolbarView.setTitle(R.string.RECENTLY_FOUND_NOTES_TOOLBAR_TITLE) includedNoteCv.cvNoteDetailImg.setImageResource(noteDetail.hint_img) includedNoteCv.iconBook.visibility = View.GONE } // 생략 }
navigation에서 넘어오는 args들을 처음에 초기화하지 않고 사용하려는 시점에 초기화하려고한다
즉, 뷰가 다 그려지고나서 (onViewCreated) noteDetail.hint_img를 처음 호출할 때 noteDetail이 args.recentlyFoundNoteDetail의 데이터 내용으로 초기화되는 것이다
위 코드에서 by라는 키워드도 있는데 이에 대해서도 같이 정리하고자 한다
코틀린에서는 by를 통해 위임을 할 수 있다
by를 사용하면 위임된 클래스가 가지는 멤버를 참조없이 호출할 수 있게 된다
private val args : RecentlyFoundNotesDetailFragmentArgs by navArgs()
private val noteDetail by lazy { args.recentlyFoundNoteDetail }이 부분에서도 by를 통해서 프로퍼티위임을 하고 있다
navArgs()라는 함수가 리턴하는 NavArgsLazy<Args>라는 위임객체를 리턴한다
이 객체는 프래그먼트의 번들에서 navigation_graph에 정의해놓은 프래그먼트의 argument를 보고 해당하는 키값을 가진 데이터를 찾는다
<fragment android:id="@+id/fragmentRecentlyFoundNotesDetail" android:name="com.jeong.sesac.sai.ui.home.RecentlyFoundNotesDetailFragment" android:label="recently_found_notes_fragment_detail_fragment" tools:layout="@layout/fragment_recently_found_notes_detail"> <argument android:name="recently_found_note_detail" app:argType="com.jeong.sesac.sai.util.WeeklyNotesInfo" /> <action android:id="@+id/action_fragmentRecentlyFoundNotesDetail_to_fragmentHome" app:destination="@+id/fragmentHome" /> </fragment>
예를 들면 위와 같이 네비게이션 그래프를 정의해놓았다고 가정해보자
safe Args가 자동으로 argument를 보고 RecentlyFoundNotesDetailFragmentArgs라는 클래스를 만든다
그리고 navArgs()가 반환하는 위임객체에서 argument에 정의해놓은 recently_found_note_detail이라는 키값을 가진 데이터를 해당 프래그먼트의 번들에서 찾는다
그리고나서 safe Args가 자동으로 만든 클래스인 RecentlyFoundNotesDetailFragmentArgs의 인스턴스를 navArgs()가 생성한다
번들에서 argument에 정의된 recently_found_note_detail라는 이름의 키값으로 데이터를 찾고, 이를 사용해 RecentlyFoundNotesDetailFragmentArgs의 인스턴스를 생성하는 것이다. 이러한 작업을 navArgs()가 반환하는 위임객체에게 위임해 대신 처리하게 한다
즉, 프로퍼티 args에 접근(get)하는 것을 navArgs()가 위임하는 위임객체한테 맡긴다는 뜻이다
그러니까 args를 사용할 때마다 navArgs()가 위임하는 위임객체는 프래그먼트의 번들에서 recently_found_note_detail라는 키값을 가진 데이터를 찾고, 찾은 데이터로 RecentlyFoundNotesDetailFragmentArgs의 인스턴스를 생성한다. 그러면 RecentlyFoundNotesDetailFragmentArgs 인스턴스를 통해 데이터에 접근할 수 있는 것이다!
코틀린에서 이런 문법들은 가끔 헷갈릴때가 있다...!
복습하자 ㅠ
반응형'Kotlin' 카테고리의 다른 글
[Kotlin] Custom Getter, Setter (1) 2024.12.19 [Kotlin] Scope functions(let, also, apply, with, run, use) (1) 2024.12.03 [kotlin] String.format (3) 2024.11.07 [Kotlin] 기본타입(Primitive Types) (3) 2024.09.28