LiveData默认带有粘性数据特征,但是很多情况下并不需要粘性数据,这时候可以通过反射去修改mLastVersion和mVersion的值,使他们相等,就可以去掉粘性数据。
封装一个单例NoStickLiveData。
object NoStickLiveData {
private val map: MutableMap<String, NoStickMutableLiveData<Any>> by lazy { HashMap() }
@Synchronized
fun <T> with(key: String, isStick: Boolean = false): NoStickMutableLiveData<T> {
if (!map.containsKey(key)) {
map[key] = NoStickMutableLiveData(isStick)
}
return map[key] as NoStickMutableLiveData<T>
}
class NoStickMutableLiveData<T> private constructor() :
MutableLiveData<T>() {
private var isStick: Boolean = false
constructor(isStick: Boolean) : this() {
this.isStick = isStick
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
if (!isStick) {
solveStick(observer)
}
}
/**
* 使用反射将mLastVersion的值改为和mVersion相同,就可以解决粘性数据问题
*/
private fun solveStick(observer: Observer<in T>) {
val liveDataClass = LiveData::class.java
//先拿到observer.mLastVersion,mLastVersion在ObserverWrapper中,ObserverWrapper又存放在mObservers中
//获取mObserversFiled
val mObserversFiled = liveDataClass.getDeclaredField("mObservers")
mObserversFiled.isAccessible = true
//获取map值,this就是LiveData
val mObserversMap: Any = mObserversFiled.get(this)
//拿到mObserversMap的class
val mObserversMapClass = mObserversMap.javaClass
//获取map的get方法
val mObserversMapGet = mObserversMapClass.getDeclaredMethod("get", Any::class.java)
mObserversMapGet.isAccessible = true
//执行map的get方法,获取ObserverWrapper
var observerWrapper: Any? = null
val invokeEntry = mObserversMapGet.invoke(mObserversMap, observer)
if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
observerWrapper = invokeEntry.value
} else {
throw Exception("observerWrapper error")
}
//获取ObserverWrapper中的mLastVersion
//由于这里获取到的的是ObserverWrapper的子类LifecycleBoundObserver或AlwaysActiveObserver
//所以需要先用superclass获取超类
val observerWrapperSuperClass = observerWrapper?.javaClass?.superclass
val mLastVersionFiled = observerWrapperSuperClass?.getDeclaredField("mLastVersion")
mLastVersionFiled?.isAccessible = true
//获取mVersion
val mVersionFiled = liveDataClass.getDeclaredField("mVersion")
mVersionFiled.isAccessible = true
//拿到mVersion的值
val mVersion = mVersionFiled.get(this)
//将mLastVersion的值设置成跟mVersion相同
mLastVersionFiled?.set(observerWrapper, mVersion)
}
}
}
使用,在NoStick1Activity先修改数据,然后再跳转到NoStick2Activity,可以看到NoStickLiveData.with传true,会正常有粘性数据,传false,就没有粘性数据。
class NoStick1Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_no_stick1)
//参数isStick为tru,表示有粘性
NoStickLiveData.with<String>("stick_data", true).value = "message----stick_data"
//参数isStick不传或者为false,表示没有粘性
NoStickLiveData.with<String>("noStick_data").value = "message----noStick_data"
findViewById<Button>(R.id.button).setOnClickListener {
startActivity(Intent(this, NoStick2Activity::class.java))
}
}
}
class NoStick2Activity : AppCompatActivity() {
private val TAG = "NoStick2Activity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_no_stick2)
NoStickLiveData.with<String>("stick_data", false).observe(this) {
Log.d(TAG, "stick_data: $it")
}
NoStickLiveData.with<String>("noStick_data").observe(this) {
Log.d(TAG, "noStick_data: $it")
}
}
}
网友评论