从0到1打造一款安卓app之10-kotlin属性委托+Lifecycle+LiveData实现在onDestroy时自动置空的对象

388 阅读1分钟

从0到1打造一款安卓app之10-kotlin属性委托+Lifecycle+LiveData实现在onDestroy时自动置空的对象

示例来原自android官方示例

有一些对象,需要在fragment生命周期onDestroy方法里手动赋值null,以防止内存泄露。如果每一个Fragment的onDestroy里都需要手动写上一句 xx=null来清除一个对象的引用,有时很容易忘记,从而导致到内存泄露。

可以使用 kotlin属性委托+Lifecycle+LiveData实现在onDestroy时自动置空的对象

class AutoClearedValue<T : Any>(val fragment: Fragment) : ReadWriteProperty<Fragment, T> {
    private var _value: T? = null

    init {
        fragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
            override fun onCreate(owner: LifecycleOwner) {
                fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
                    viewLifecycleOwner?.lifecycle?.addObserver(object: DefaultLifecycleObserver {
                        override fun onDestroy(owner: LifecycleOwner) {
                            LogUtils.d("AutoClearedValue","onDestroy _value:${_value}")
                            _value = null
                        }
                    })
                }
            }
        })
    }

    override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        return _value ?: throw IllegalStateException(
            "should never call auto-cleared-value get when it might not be available"
        )
    }

    override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
        _value = value
    }
}

/**
 * Creates an [AutoClearedValue] associated with this fragment.
 */
fun <T : Any> Fragment.autoCleared() = AutoClearedValue<T>(this)

内存泄露示例

class xxxFragment : BaseFragment() {

    private var dataBinding:FragmentxxxxBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        dataBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_xxxx,container, false)
        return dataBinding.root
    }
}

dataBinding对象如果不在onDestroy对象里置空,则有时候会看到内存泄露的提示

只需要把上面的 private var dataBinding:FragmentxxxxBinding

修改成 private var dataBinding:FragmentHomeMessageBinding by autoCleared()即可