반응형
현업에서 다양한 개발자와 명세를 맞추어 개발하는 것은 매우 중요하다. 파편화된 코드 스타일은 곧 가독성을 해치고, 버그가 발생하거나 기능을 추가할 때 자칫하면 개발 효율성을 크게 저하시킬 수 있다.
MVVM 패턴을 사용할때 다음은 ViewBinding을 강제하는 Activity, Fragment BoilerPlate Class이다. Generic을 활용하기 때문에 모든 하위 클래스는 이를 상속받아 보다 쉽게 ViewBinding을 강제한 코드를 빠르게 구현할 수 있다.
뷰 바인딩
https://developer.android.com/topic/libraries/view-binding?hl=ko
BaseActivity
abstract class BaseBindActivity<V : ViewDataBinding>(
@LayoutRes private val layoutResId: Int
) : AppCompatActivity() {
protected lateinit var binding: V
lateinit var toolbar: Toolbar
protected abstract val layoutToolbarID: Int
val realm: Realm = Realm.getDefaultInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, layoutResId)
binding.lifecycleOwner = this
if (layoutToolbarID != 0) {
toolbar = findViewById(layoutToolbarID)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = ""
}
setStatusBarTransparent()
initLayoutAttributes()
}
abstract fun initLayoutAttributes()
override fun onDestroy() {
super.onDestroy()
if (!realm.isClosed) realm.close()
}
}
Realm 이나 RxJava 사용 시에도 boilerplate내에서 lifecycle을 관리하면 개발자가 실수할 확률도 줄어든다.
사용 시에는 다음과 같이 상속받아 사용한다.
class ExampleActivity : BaseBindActivity<ActivityExampleBinding>(R.layout.activity_example) {
override val layoutToolbarID: Int
get() = R.id.toolbar_center_title // 사용하지 않으면 0
override fun initLayoutAttributes() {
// 레이아웃 관련 초기화
}
}
BaseFragment
Fragment는 ViewBindingHolder를 활용한다.
abstract class BaseBindFragment<V : ViewDataBinding>(
@LayoutRes private val layoutResId: Int
) : Fragment(),
ViewBindingHolder<V> by ViewBindingHolderImpl() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = initBinding(DataBindingUtil.inflate(inflater, layoutResId, null, false), this) {}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initLayoutAttributes()
}
protected abstract fun initLayoutAttributes()
}
ViewBindingHolder
interface ViewBindingHolder<T : ViewBinding> {
val binding: T?
fun initBinding(binding: T, fragment: Fragment, onBound: (T.() -> Unit)?): View
fun requireBinding(block: (T.() -> Unit)? = null): T
}
class ViewBindingHolderImpl<T : ViewBinding> : ViewBindingHolder<T>, LifecycleObserver {
override var binding: T? = null
var lifecycle: Lifecycle? = null
private lateinit var fragmentName: String
override fun requireBinding(block: (T.() -> Unit)?) =
binding?.apply { block?.invoke(this) } ?: throw IllegalStateException("Accessing binding outside of Fragment lifecycle: $fragmentName")
override fun initBinding(binding: T, fragment: Fragment, onBound: (T.() -> Unit)?): View {
this.binding = binding
lifecycle = fragment.viewLifecycleOwner.lifecycle
lifecycle?.addObserver(this)
fragmentName = fragment::class.simpleName ?: "N/A"
onBound?.invoke(binding)
return binding.root
}
}
마찬가지로 다음과 같이 상속받아 사용한다.
class ExampleFragment : BaseBindFragment<FragmentExampleBinding>(R.layout.fragment_example) {
override fun initLayoutAttributes() {
// 레이아웃 관련 초기화
}
}
매우 간결하게 사용할 수 있다. 나머지는 부모 클래스가 다~ 알아서 해준다.
반응형
'Android' 카테고리의 다른 글
RxBus - Rxjava로 전역 callback으로 구현하기 (0) | 2021.12.08 |
---|---|
[Android] Firebase Remote Config 사용하기 (0) | 2021.12.06 |
Google Admob 보상형 광고 적용 및 최적화 하기 (0) | 2020.05.04 |
Google Admob 광고 사용하기 (0) | 2020.05.04 |