通用工具类:
fun<T> T.ifNotIs(compareValue:T):T?{
return if (this != compareValue) {
this
} else {
null
}
}
fun<T> T?.then(block:(T)->Unit) {
if (this != null) {
try {
block(this)
} catch (e: Exception) {
LogUtils.e("LogicExt--then ",e)
}
}
}
class Do<Item1,Item2>(block: Do<Item1,Item2>.() -> Unit) {
init {
block()
}
fun<You:List<Item1>,Me:List<Item2>> You.loveTogetherWith(me:Me, block:(Item1, Item2)->Unit):Boolean{
if (size != me.size) {
return false
}
forEachIndexed { index, yourBaby ->
block(yourBaby, me[index])
}
return true
}
}
//使用方式
//private val mDialogTimePicker by lazyMeNeedKFC{LBDatePickerDialog(mContext)}
fun<T> Any.lazyMeNeedKFC(initializer:()->T):Lazy<T>{
return ValLazyLoading(initializer)
}
private class ValLazyLoading<T>(private val initializer:()->T):Lazy<T>{
private var cached: T? = null
override val value: T
get() {
return cached ?: initializer().also {
cached = it
}
}
override fun isInitialized() = cached != null
}
//方法调用链,用于提供顺序执行内容的能力
suspend fun CoroutineScope.exeChain(delay:Long,dp:CoroutineDispatcher=Dispatchers.Main,block:suspend ()->Unit):CoroutineScope {
if (delay <= 0) {
withContext(dp){
block()
}
return this
} else {
delay(delay)
withContext(dp){
block()
}
return this
}
}
//exeChain使用方式:
CoroutineScope(Dispatchers.Main).launch {
for (i in 0 until 1000) {
exeChain(0, dp = Dispatchers.IO) {
Log.d(TAG, "onCreate: 1 time=${getTime()} ${Thread.currentThread().name}")
}.exeChain(0, dp = Dispatchers.Default) {
Log.d(TAG, "onCreate: 2 time=${getTime()} ${Thread.currentThread().name}")
}.exeChain(0, dp = Dispatchers.IO) {
Log.d(TAG, "onCreate: 3 time=${getTime()} ${Thread.currentThread().name}")
}.exeChain(0, dp = Dispatchers.Main){
Log.d(TAG, "onCreate: 4 time=${getTime()} ${Thread.currentThread().name}")
}
}
}
//打印日志
//D/MainActivity: onCreate: 1 time=17:00:02 DefaultDispatcher-worker-1 tDispatcher-worker-1
//D/MainActivity: onCreate: 2 time=17:00:03 DefaultDispatcher-worker-1 tDispatcher-worker-1
//D/MainActivity: onCreate: 3 time=17:00:03 DefaultDispatcher-worker-1 tDispatcher-worker-1
//D/MainActivity: onCreate: 4 time=17:00:03 main
//D/MainActivity: onCreate: 1 time=17:00:03 DefaultDispatcher-worker-4 tDispatcher-worker-4
//D/MainActivity: onCreate: 2 time=17:00:03 DefaultDispatcher-worker-4 tDispatcher-worker-4
//D/MainActivity: onCreate: 3 time=17:00:03 DefaultDispatcher-worker-3 tDispatcher-worker-3
//D/MainActivity: onCreate: 4 time=17:00:03 main
//D/MainActivity: onCreate: 1 time=17:00:03 DefaultDispatcher-worker-5 tDispatcher-worker-5
//D/MainActivity: onCreate: 2 time=17:00:03 DefaultDispatcher-worker-5 tDispatcher-worker-5
//D/MainActivity: onCreate: 3 time=17:00:03 DefaultDispatcher-worker-3 tDispatcher-worker-3
//D/MainActivity: onCreate: 4 time=17:00:03 main
//D/MainActivity: onCreate: 1 time=17:00:03 DefaultDispatcher-worker-2 tDispatcher-worker-2
//D/MainActivity: onCreate: 2 time=17:00:03 DefaultDispatcher-worker-2 tDispatcher-worker-2
//D/MainActivity: onCreate: 3 time=17:00:03 DefaultDispatcher-worker-2 tDispatcher-worker-2
//D/MainActivity: onCreate: 4 time=17:00:03 main
//D/MainActivity: onCreate: 1 time=17:00:03 DefaultDispatcher-worker-1 tDispatcher-worker-1
//D/MainActivity: onCreate: 2 time=17:00:03 DefaultDispatcher-worker-1 tDispatcher-worker-1
//D/MainActivity: onCreate: 3 time=17:00:03 DefaultDispatcher-worker-4 tDispatcher-worker-4
//D/MainActivity: onCreate: 4 time=17:00:03 main
Kotlin创建Tuple:
data class Tuple1<out A>(val _1: A) : Tuple(1)
data class Tuple2<out A, out B>(val _1: A, val _2: B) : Tuple(2)
data class Tuple3<out A, out B, out C>(val _1: A, val _2: B, val _3: C) : Tuple(3)
data class Tuple4<out A, out B, out C, out D>(val _1: A, val _2: B, val _3: C, val _4: D) : Tuple(4)
data class Tuple5<out A, out B, out C, out D, out E>(val _1: A, val _2: B, val _3: C, val _4: D, val _5: E) : Tuple(5)
open class Tuple(val size: Int) {
companion object {
operator fun <A> invoke(_1: A): Tuple1<A> = Tuple1(_1)
operator fun <A, B> invoke(_1: A, _2: B): Tuple2<A, B> = Tuple2(_1, _2)
operator fun <A, B, C> invoke(_1: A, _2: B, _3: C): Tuple3<A, B, C> = Tuple3(_1, _2, _3)
operator fun <A, B, C, D> invoke(_1: A, _2: B, _3: C, _4: D): Tuple4<A, B, C, D> = Tuple4(_1, _2, _3, _4)
operator fun <A, B, C, D, E> invoke(_1: A, _2: B, _3: C, _4: D, _5: E): Tuple5<A, B, C, D, E> = Tuple5(_1, _2, _3, _4, _5)
}
}
通用Dialog基类:
abstract class DialogSafeBase(var time:Long=3_000L): LifecycleObserver {
private var mTimer: CountDownTimer = object : CountDownTimer(time, 1000) {
override fun onTick(millisUntilFinished: Long) {
}
override fun onFinish() {
LogUtils.d("DialogSafeBase--onFinish this=$this ")
mDialogInternal?.dismiss()
}
}
private class EmptyView(context: Context) : View(context)
protected abstract fun theme(): Int
protected abstract fun layoutID(): Int
protected abstract fun useDataBinding(): Boolean
protected abstract fun useViewBinding(): Boolean
protected abstract fun initView(root: View)
protected abstract fun setData()
protected abstract fun initConfig(window: Window?)
protected abstract fun onDismiss()
protected abstract fun onShowListener()
protected open fun onCreateDataBindingView(
inflater: LayoutInflater
): View {
return EmptyView(inflater.context)
}
protected open fun onCreateViewBinding(inflater: LayoutInflater): View {
return EmptyView(inflater.context)
}
private inner class DialogInternal(val mContext: Context) :
Dialog(mContext, theme()) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = LayoutInflater.from(mContext)
val view = if (useDataBinding()) {
onCreateDataBindingView(inflater)
} else {
if (useViewBinding()) {
onCreateViewBinding(inflater)
} else {
inflater.inflate(layoutID(), null)
}
}
initView(view)
setContentView(view)
initDefaultConfig()
initConfig(window)
}
override fun onStart() {
setData()
super.onStart()
}
private fun initDefaultConfig() {
val screenWH = getScreenWH()
window?.apply {
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
attributes?.apply {
width = (screenWH[0] * 0.5f).toInt()
height = (screenWH[0] * 0.5f).toInt()
attributes = this
}
setBackgroundDrawableResource(R.color.transparent)
}
}
}
protected lateinit var mContext:Context
private var mDialogInternal:DialogInternal?=null
private var mIgnoreLifeStop=false
/**
* repeatShow:是否允许重复显示(重复dismiss->show) true:允许 false:不允许
*/
fun show(context: Context, lifecycle: Lifecycle, isAutoDismiss: Boolean = false, cancelOutside:Boolean=true,repeatShow:Boolean=true,ignoreLifeStop:Boolean=false) {
mIgnoreLifeStop=ignoreLifeStop
LogUtils.d("DialogSafeBase--show this=$this")
mDialogInternal?:apply {
LogUtils.d("DialogSafeBase--show init dialog")
mDialogInternal=DialogInternal(context)
}
mContext=context
mDialogInternal?.apply {
if (isShowing) {
if (repeatShow) {
dismiss()
} else {
return
}
}
setOnShowListener {onShowListener() }
setOnDismissListener {
lifecycle.removeObserver(this@DialogSafeBase)
mTimer.cancel()
onDismiss()
}
setCanceledOnTouchOutside(cancelOutside)
show()
}
lifecycle.addObserver(this)
if (isAutoDismiss) {
mTimer.cancel()
mTimer.start()
}
}
fun dismiss() {
LogUtils.d("DialogSafeBase--dismiss this=$this")
mDialogInternal?.apply {
if (isShowing) {
mDialogInternal!!.dismiss()
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onHostLifeStop(owner: LifecycleOwner) {//自动关闭弹框,通用情况下,
// 宿主stop的时候需要关闭弹框,比如主界面到设置界面,主界面没有destroy,
// 但是这时候不能显示主界面的弹框,防止遮蔽设置界面视野
//但是对于娱乐弹框来说,他必须始终显示已确保进入其他app后,能够显示浮动按钮,用于退出
LogUtils.d("DialogSafeBase--onHostLifeDestroy ON_STOP mIgnoreLifeStop=$mIgnoreLifeStop")
if (!mIgnoreLifeStop) {
dismiss()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onHostLifeDestroy(owner: LifecycleOwner) {//自动关闭弹框,对于destroy来说,无论什么情况都必须关闭弹框
LogUtils.d("DialogSafeBase--onHostLifeDestroy ON_DESTROY")
dismiss()
}
protected fun getScreenWH(): Array<Int> {
val wm = mContext.applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val dm = DisplayMetrics()
wm.defaultDisplay.getRealMetrics(dm)
return arrayOf(dm.widthPixels, dm.heightPixels)
}
}
<style name="DialogWarnning" parent="Theme.AppCompat.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
<!-- <item name="android:windowBackground">@android:color/transparent</item>-->
<item name="android:windowIsFloating">true</item>
<item name="android:padding">0dp</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:backgroundDimEnabled">false</item><!--activity不变暗-->
</style>