안드로이드 LayoutInflater 사용하기
LayoutInflater
는 안드로이드에서 View
를 만드는 가장 기본적인 방법입니다.
Fragment
의 View
를 만들거나 RecyclerView
에서 ViewHolder
를 만들때, CustomView
에서 xml로 정의된 View
를 merge
할 때 등 여러곳에서 사용됩니다.
이 글에서는 LayoutInflater
를 적절히 사용하는 방법과, 비동기적으로 LayoutInflater
를 사용 하는 방법을 알아보도록 하겠습니다.
LayoutInflater 생성하기
Context#getSystemService()
가장 기본적인 방법으로 context
에서 LayoutInflater
를 가져오는 방법입니다.
val inflater: LayoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
Activity#getLayoutInflater()
Activity
에서는 LayoutInflater
를 쉽게 얻어올수 있도록 getLayoutInflater()
를 제공합니다. Activity
는 자신 window
의 LayoutInflater
를 사용합니다.
val inflater: LayoutInflater = getLayoutInflater()
LayoutInflater.from()
이 방법은 가장 자주 사용하는 방법으로, LayoutInflater
에 static
으로 정의되어있는 LayoutInflater.from
을 통해 LayoutInflater
를 만드는 방법입니다. 내부적으로 context#getSystemService
를 호출 하고 있으며, 같은 context
에서는 같은 객체를 리턴하기 때문에 굳이 멤버 변수로 선언해 놓지 않고 필요할 때마다 호출해서 사용해도 괜찮습니다.
val inflater: LayoutInflater = LayoutInflater.from(context)
RecyclerView에서 ViewHolder를 만들때 LayoutInflater를 반복적으로 사용하기 때문에, kotlin extension을 사용해 편하게 사용 중 입니다.
fun ViewGroup.inflate(resId: Int, attach: Boolean = false): View
= LayoutInflater.from(context).inflate(resource, this, attachToRoot)// ViewHolder(view = parent.inflate(R.layout.item_view))
AsyncLayoutInflater
LayoutInflate는 동기적으로(synchronous) 뷰를 생성 하기 때문에, support package에서는 비동기적으로 뷰를 만들 수 있는 AsyncLayoutInflater를 제공합니다. XML내의 뷰 hierarchy가 복잡하거나 UI스레드에서 inflate하는데 시간이 너무 오래걸린다면 사용 할 수 있습니다.
val inflater = AsyncLayoutInflater(context)
inflater.inflate(R.layout.my_layout, parent) { view, resId, parent ->
// parent.addView(view)
}
간단하게 비동기로 뷰를 생성 할수 있지만. 몇가지 주의할 점이 있습니다
1. parent의 generateLayoutParam()
이 thread safe해야 합니다
2. 생성자에서 Handler
를 만들거나 Looper.myLooper()
를 사용하면 안됩니다.
3. LayoutInflater.Factory
를 사용 할 수 없습니다.
4. Fragment
를 inflate
할 수 없습니다.
View inflate하기
inflater
에서 View
객체를 만들기 위해서는 inflater
를 사용 하면 됩니다.
inflate(resource: Int, root: ViewGroup?, attachToRoot: Boolean)
- resource:
View
를 만들고 싶은 레이아웃 파일의 id입니다.R.layout.my_view
- root: 생성될
View
의 parent를 명시해줍니다.null
일 경우에는LayoutParams
값을 설정 할 수 없기 때문에 XML내의 최상위android:layout_xxxxx
값들이 무시되고 merge tag를 사용 할 수 없습니다. - attachToRoot:
true
로 설정해 줄 경우root
의 자식View
로 자동으로 추가됩니다. 이때root
는null
일 수 없습니다. - return:
attachToRoot
에 따라서 리턴값이 달라집니다.true
일 경우root
가,false
일 경우 XML내 최상위 뷰가 리턴됩니다.
View.inflate()
View
에서는 LayoutInflater
의 inflate
까지 한번에 실행하는 View.inflate()
를 제공 하고 있습니다. (내부에서는 LayoutInflater.inflate
를 수행함) 이 때 주의할점은 parent
가 null
이 아니면 자동으로 attach됩니다.
View.inflate(context, R.layout.my_layout, parent)
요약
val inflater = LayoutInflater.from(context)
...
val view = inflater.inflate(R.layout.my_view, parent, false)
parent.addView(view)
...
inflater.inflate(R.layout.my_view, parent, true)
...
View.inflate(context, R.layout.my_view, parent)
- XML레이아웃 파일에서 뷰를 생성할때는 LayoutInflater를 이용해야 한다.
- 비동기로 뷰를 생성할때는 AsyncLayoutInflater를 이용 할 수 있다.
- LayoutInflater는 LayoutInflater.from(context)를 이용하여 얻는다.
- LayoutInflater객체의 inflate메서드를 이용하여 새로운 뷰를 생성 할 수 있다.
- root를 지정하지 않을 경우 xml상의 최상위 뷰의 android:layout_xxxxx들은 무시된다. (참고자료)
- attachToRoot를 true로 설정할경우 뷰를 생성할때 자동으로 root의 자식으로 추가된다.