Skip to content

Instantly share code, notes, and snippets.

@hkusu
Last active February 15, 2021 05:43
Show Gist options
  • Save hkusu/8640109b66a80e775c3cc2d21ff95498 to your computer and use it in GitHub Desktop.
Save hkusu/8640109b66a80e775c3cc2d21ff95498 to your computer and use it in GitHub Desktop.
package io.github.hkusu.sample.ui
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import io.github.hkusu.sample.databinding.MainFragmentBinding
class MainFragment : Fragment(R.layout.main_fragment) {
private val binding: MainFragmentBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.message.text = "テストテスト"
}
override fun onDestroy() {
super.onDestroy()
// この時点でFragment#getView()は死んでいる
safeViewBinding {
binding.message.text = "安全!"
}
}
}
package io.github.hkusu.sample.ext
import android.util.Log
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.get
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
// ref: https://satoshun.github.io/2020/01/fragment-view-memory-leak/
// https://satoshun.github.io/2019/04/jetpack-coroutine-support/
fun <T : ViewDataBinding> AppCompatActivity.viewBinding(): ReadOnlyProperty<AppCompatActivity, T> {
return object : ReadOnlyProperty<AppCompatActivity, T> {
override fun getValue(thisRef: AppCompatActivity, property: KProperty<*>): T {
val view = thisRef.findViewById<ViewGroup>(android.R.id.content)[0]
val binding = DataBindingUtil.bind<T>(view)!!
binding.lifecycleOwner = thisRef
return binding
}
}
}
fun <T : ViewDataBinding> Fragment.viewBinding(): ReadOnlyProperty<Fragment, T> {
return object : ReadOnlyProperty<Fragment, T> {
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
val view = thisRef.view ?: throw FragmentViewNotFoundException()
val binding = DataBindingUtil.bind<T>(view)!!
binding.lifecycleOwner = thisRef.viewLifecycleOwner
return binding
}
}
}
// Fragment.viewBinding() 用
class FragmentViewNotFoundException : Exception("Fragment#getView() returned null.")
// Fragment.viewBinding() 用。コールバックや遅延実行等でonDestroyView()後にBindingを触る可能性がある場合に利用する
inline fun Fragment.safeViewBinding(block: () -> Unit) {
try {
block.invoke()
} catch (e: FragmentViewNotFoundException) {
Log.w(this::class.java.simpleName, e.message!!)
}
}
// そもそも binding を Nullable にして安全に扱いたい場合は Fragment.viewBinding() の代わりにこちらを利用する
fun <T : ViewDataBinding> Fragment.safeViewBinding(): ReadOnlyProperty<Fragment, T?> {
return object : ReadOnlyProperty<Fragment, T?> {
override fun getValue(thisRef: Fragment, property: KProperty<*>): T? {
val view = thisRef.view ?: return null
val binding = DataBindingUtil.bind<T>(view)!!
binding.lifecycleOwner = thisRef.viewLifecycleOwner
return binding
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment