-
Handler内存泄露 未及时处理的message持有handler的强引用; 使用handler.removeMessages(what)销毁消息;
-
Room索引使用
什么情况下要避免使用索引?
虽然索引的目的在于提高数据库的性能,但这里有几个情况需要避免使用索引。使用索引时,应重新考虑下列准则:
- 索引不应该使用在较小的表上。
- 索引不应该使用在有频繁的大批量的更新或插入操作的表上。
- 索引不应该使用在含有大量的 NULL 值的列上。
- 索引不应该使用在频繁操作的列上。
- Room外键
外键只是保证数据的一致性,并不能给系统性能带来任何好处,在数据量特别大的情况下,每一次约束检查必然导致性能的下降,所以由于外键导致的插入数据变慢会随着数据量的增长而越来越严重
- Android计算dip(dp):dp = px * requireContext().resources?.displayMetrics?.density
- Android富文本展示官方推荐:SpannedString、SpannableString、SpannableStringBuilder
- Android腾讯地图去除logo水印
/**
* 重写腾讯地图管理SupportMapFragmentFragment类
* 去除腾讯地图logo水印
* @author decheng.li 2023/1/13
*/
class MapFragment: SupportMapFragment() {
override fun onCreateView(
layoutinflater: LayoutInflater,
viewgroup: ViewGroup?,
bundle: Bundle?
): View? {
val mapView: MapView = super.onCreateView(layoutinflater, viewgroup, bundle) as MapView
mapView.viewTreeObserver?.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
//获取logo水印所在的图层并隐藏该图层,目前logo是第二层图层
mapView.getChildAt(1)?.visibility = View.INVISIBLE
mapView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
return super.onCreateView(layoutinflater, viewgroup, bundle)
}
}
- kotlin LiveData自定义MutableListLiveData,实现对集合数据元素变动、size变化、及整体数据改变进行实时观察响应:
/**
* 自定义LiveData,存储集合数据,支持监听数量变化
*/
open class MutableListLiveData<T>(mutableList: MutableList<T>?) {
companion object {
private const val START_VERSION = -1
}
private var mData: MutableList<T>? = mutableList
private var mVersion = 0
private var mSizeVersion = 0
var mActiveCount = 0
private var mChangingActiveState = false
private var mDispatchingValue = false
private var mDispatchInvalidated = false
private val mObservers: SafeIterableMap<Observer<Any>, ObserverWrapper> =
SafeIterableMap<Observer<Any>, ObserverWrapper>()
init {
mVersion = START_VERSION + 1
mSizeVersion = START_VERSION + 1
}
fun getData(): MutableList<T>? {
return mData
}
fun setValue(value: MutableList<T>?) {
assertMainThread("setValue")
mVersion++
mData = value
dispatchingValue(null)
}
// fun postValue(value: MutableList<T>?) {
// super.postValue(value)
// }
fun addAll(value: MutableList<T>) {
assertMainThread("addValue")
mSizeVersion++
mData?.addAll(value)
dispatchingValue(null)
}
fun removeValue(value: T) {
assertMainThread("addValue")
mSizeVersion++
mData?.remove(value)
dispatchingValue(null)
}
private fun assertMainThread(methodName: String) {
check(ArchTaskExecutor.getInstance().isMainThread) {
("Cannot invoke " + methodName + " on a background"
+ " thread")
}
}
@MainThread
open fun observe(owner: LifecycleOwner, observer: Observer<Any>) {
assertMainThread("observe")
if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
// ignore
return
}
val wrapper = LifecycleBoundObserver(owner, observer)
val existing: ObserverWrapper? = mObservers.putIfAbsent(observer, wrapper)
require(!(existing != null && !existing.isAttachedTo(owner))) {
("Cannot add the same observer"
+ " with different lifecycles")
}
if (existing != null) {
return
}
owner.lifecycle.addObserver(wrapper)
}
@MainThread
fun observeSize(owner: LifecycleOwner, observer: Observer<Any>) {
assertMainThread("observeSize")
if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
// ignore
return
}
val wrapper = SizeLifecycleBoundObserver(owner, observer)
val existing: ObserverWrapper? = mObservers.putIfAbsent(observer, wrapper)
require(!(existing != null && !existing.isAttachedTo(owner))) {
("Cannot add the same observer"
+ " with different lifecycles")
}
if (existing != null) {
return
}
owner.lifecycle.addObserver(wrapper)
}
private fun dispatchingValue(initiator: ObserverWrapper?) {
var initiator: ObserverWrapper? = initiator
if (mDispatchingValue) {
mDispatchInvalidated = true
return
}
mDispatchingValue = true
do {
mDispatchInvalidated = false
if (initiator != null) {
considerNotify(initiator)
initiator = null
} else {
val iterator: Iterator<Map.Entry<Observer<Any>, ObserverWrapper?>> =
mObservers.iteratorWithAdditions()
while (iterator.hasNext()) {
considerNotify(iterator.next().value)
if (mDispatchInvalidated) {
break
}
}
}
} while (mDispatchInvalidated)
mDispatchingValue = false
}
private fun considerNotify(observer: ObserverWrapper?) {
if (observer?.mActive == false) {
return
}
if (observer?.shouldBeActive() == false) {
observer.activeStateChanged(false)
return
}
// if (observer?.mLastVersion!! >= mVersion) {
// return
// }
// observer.mLastVersion = mVersion
if (observer is SizeLifecycleBoundObserver) {
if (observer.mLastVersion >= mSizeVersion) {
return
}
observer.mLastVersion = mSizeVersion
observer.mObserver.onChanged(mData?.size)
} else {
if (observer?.mLastVersion!! >= mVersion) {
return
}
observer.mLastVersion = mVersion
observer.mObserver.onChanged(mData)
}
}
@MainThread
open fun removeObserver(observer: Observer<Any>) {
assertMainThread("removeObserver")
val removed = mObservers.remove(observer) ?: return
removed.detachObserver()
removed.activeStateChanged(false)
}
private abstract inner class ObserverWrapper constructor(observer: Observer<Any>) {
val mObserver: Observer<Any>
var mActive = false
var mLastVersion = START_VERSION
init {
mObserver = observer
}
abstract fun shouldBeActive(): Boolean
open fun isAttachedTo(owner: LifecycleOwner?): Boolean {
return false
}
open fun detachObserver() {}
fun activeStateChanged(newActive: Boolean) {
if (newActive == mActive) {
return
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive
changeActiveCounter(if (mActive) 1 else -1)
if (mActive) {
dispatchingValue(this)
}
}
}
/**
* 监听集合重置变化
*/
private open inner class LifecycleBoundObserver(open val mOwner: LifecycleOwner, observer: Observer<Any>) :
ObserverWrapper(observer), LifecycleEventObserver {
override fun shouldBeActive(): Boolean {
return mOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
}
override fun onStateChanged(
source: LifecycleOwner,
event: Lifecycle.Event
) {
var currentState = mOwner.lifecycle.currentState
if (currentState == Lifecycle.State.DESTROYED) {
removeObserver(mObserver)
return
}
var prevState: Lifecycle.State? = null
while (prevState != currentState) {
prevState = currentState
activeStateChanged(shouldBeActive())
currentState = mOwner.lifecycle.currentState
}
}
override fun isAttachedTo(owner: LifecycleOwner?): Boolean {
return mOwner === owner
}
override fun detachObserver() {
mOwner.lifecycle.removeObserver(this)
}
}
/**
* 监听集合数据size变化
*/
private inner class SizeLifecycleBoundObserver(override val mOwner: LifecycleOwner, observer: Observer<Any>) :
LifecycleBoundObserver(mOwner, observer), LifecycleEventObserver
@MainThread
open fun changeActiveCounter(change: Int) {
var previousActiveCount: Int = mActiveCount
mActiveCount += change
if (mChangingActiveState) {
return
}
mChangingActiveState = true
try {
while (previousActiveCount != mActiveCount) {
val needToCallActive = previousActiveCount == 0 && mActiveCount > 0
val needToCallInactive = previousActiveCount > 0 && mActiveCount == 0
previousActiveCount = mActiveCount
if (needToCallActive) {
onActive()
} else if (needToCallInactive) {
onInactive()
}
}
} finally {
mChangingActiveState = false
}
}
protected open fun onInactive() {}
protected open fun onActive() {}
}