场景
1、在开发中一个页面会有多个请求,同时并发请求,返回数据时间有快有慢,loading在此时可能会在第一个返回接口时消失,然而其他接口还没返回数据。
2、在一个页面几个请求是串行请求,在第一个接口返回数据后消失,在第二个请求开始时显示,就会出现反复显示->>消失->>显示->>消失的问题。
思路
(1)并发:
开始请求:
请求A→计数器+1→show();
请求B→计数器+1;
请求C→计数器+1;
结束请求:
请求B完成→计数器-1→判断 若计数器<=0 则延时500毫秒dismiss()
请求C完成→计数器-1→判断 若计数器<=0 则延时500毫秒dismiss()
请求A完成→计数器-1→判断 若计数器<=0 则延时500毫秒dismiss()
(2)串行:
请求A→计数器+1→show()→请求A完成→计数器-1→判断 若计数器<=0 则延时500毫秒dismiss()
→请求B(此时还未dismiss) →计数器+1→请求B完成→计数器-1→判断 若计数器<=0 则延时500毫秒dismiss()
整体流程:
解决方案
具体逻辑在代码注释中;
/**
* 静态LoadingUtil
* 用到思想:计数+延时消失
* 解决多个请求时,弹窗立即显示、消失、显示、消失问题
*/
object LoadingUtil {
/**
* 记录请求数量,计数
*/
private val reqCount: AtomicInteger by lazy {
AtomicInteger()
}
/**
* 用来显示的Dialog
*/
private var loadingDialog: LoadingDialog? = null
/**
* 上一个请求显示loading的context标记
*/
private var lastFlag: String = ""
/**
* 当前请求显示loading的context标记
*/
private var currentFlag: String = ""
/**
* 等待下一次新的请求的时间,可以适当修改
*/
private val waitTime: Long= 500L
/**
* 用来延时消失
*/
private val handler: Handler by lazy {
Handler(Looper.getMainLooper())
}
/**
* 是否准备dismiss
*/
private var isReadyToDismiss: Boolean = false
private var mOnDismissListener: DialogInterface.OnDismissListener? = null
fun setOnDismissListener(listener: DialogInterface.OnDismissListener) {
this.mOnDismissListener = listener
}
/**
* 建议在页面正在显示,生命周期大于等于onResume时调用,
* 如
* if (lifecycle.currentState == Lifecycle.State.RESUMED) {
LoadingUtil.show(this, text)
}
*/
fun show(context: Context, msg: String? = "加载中...") {
//把当前标记赋值给上一个标志lastFlag
lastFlag = this.currentFlag
//获取当前请求显示的标记
this.currentFlag = context.toString()
//判断上一个标志和当前页面标志是否一致
if (currentFlag != lastFlag) {
//不一致:说明不是同一个页面 ->> 进行dismiss
if (loadingDialog != null) {
lastFlag = ""
reqCount.set(0)
forceDismiss()
}
}
if (loadingDialog == null) {
loadingDialog = LoadingDialog(context, msg)
}
if (!loadingDialog?.isShowing!!) {
loadingDialog?.show()
loadingDialog?.setOnDismissListener {
mOnDismissListener?.onDismiss(it)
}
} else {
//如果在消失前,又来了请求,在handle里就不去消失
isReadyToDismiss = false
}
startReq()
}
/**
* 强制dismiss
* 在切换页面时、在不是同一个页面时
* 如在生命周期:onPause
*/
fun forceDismiss() {
loadingDialog ?: return
try {
if (loadingDialog?.isShowing!!) {
loadingDialog?.dismiss()
}
loadingDialog = null
isReadyToDismiss = false
currentFlag = ""
lastFlag = ""
mOnDismissListener = null
reqCount.set(0)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun dismiss(flag: Any) {
if (TextUtils.equals(currentFlag, flag.toString()) || currentFlag.isEmpty()) {
endReq()
}
}
//开始计数(可能多个请求)
private fun startReq() {
when {
//当前标志为空,第一次进入此页面,请求数为1
currentFlag.isEmpty() -> {
reqCount.set(1)
}
//同一个页面,多个请求,请求数自增
TextUtils.equals(currentFlag, lastFlag) -> {
reqCount.incrementAndGet()
}
else -> {//不同页面,请求数重置为1
reqCount.set(1)
}
}
}
//计数
private fun endReq() {
when {
currentFlag.isEmpty() -> {
reqCount.set(0)
}
//同一个页面,请求数自减
TextUtils.equals(currentFlag, lastFlag) -> {
reqCount.decrementAndGet()
}
else -> {
reqCount.set(0)
}
}
//请求都结束了,去消失
if (reqCount.get() <= 0) {
reqCount.set(0)
loadNull()
}
}
/**
* 延时回收
*/
private fun loadNull() {
loadingDialog ?: return
if (isReadyToDismiss) {
return
}
isReadyToDismiss = true
//500毫秒后结束,解决多个请求同时show和dismiss时dialog闪烁,
try {
handler.postDelayed({
//如果有请求进来,则不消失
if (isReadyToDismiss && loadingDialog != null && reqCount.get() == 0) {
if (loadingDialog?.isShowing!!) {
loadingDialog?.dismiss()
}
loadingDialog = null
mOnDismissListener = null
currentFlag = ""
lastFlag = ""
reqCount.set(0)
isReadyToDismiss = false
}
}, waitTime)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
使用:
在BaseActivity/BaseFragment中定义,子类可以直接调用
override fun onPause() {
super.onPause()
LoadingUtil.forceDismiss()
}
fun showLoading(text: String? = "加载中...") {
if (lifecycle.currentState == Lifecycle.State.STARTED) {
LoadingUtil.show(this, text)
}
}
fun dismissLoading() {
LoadingUtil.dismiss(this)
}
补充个java版的代码,不过没经过测试:
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import com.zys.baselib.dialog.LoadingDialog;
import java.util.concurrent.atomic.AtomicInteger;
public class LoadingUtil {
private static AtomicInteger reqCount = new AtomicInteger();
/**
* 用来显示的Dialog
*/
private static LoadingDialog loadingDialog = null;
/**
* 上一个请求显示loading的context标记
*/
private static String lastFlag = "";
/**
* 当前请求显示loading的context标记
*/
private static String currentFlag = "";
/**
* 等待下一次新的请求的时间,可以适当修改
*/
private static Long waitTime = 500L;
/**
* 用来延时消失
*/
private static Handler handler=new Handler(Looper.getMainLooper());
/**
* 是否准备dismiss
*/
private static Boolean isReadyToDismiss = false;
public static void show(Context context , String msg) {
//把当前标记赋值给上一个标志lastFlag
lastFlag = currentFlag;
//获取当前请求显示的标记
currentFlag = context.toString();
//判断上一个标志和当前页面标志是否一致
if (!currentFlag.equals(lastFlag)) {
//不一致:说明不是同一个页面 ->> 进行dismiss
if (loadingDialog != null) {
lastFlag = "";
reqCount.set(0);
forceDismiss();
}
}
if (loadingDialog == null) {
loadingDialog = new LoadingDialog(context, msg);
}
if (!loadingDialog.isShowing()) {
loadingDialog.show();
} else {
//如果在消失前,又来了请求,在handle里就不去消失
isReadyToDismiss = false;
}
startReq();
}
/**
* 强制dismiss
* 在切换页面时、在不是同一个页面时
* 如在生命周期:onPause
*/
public static void forceDismiss() {
if (loadingDialog==null)return;
try {
if (loadingDialog.isShowing()) {
loadingDialog.dismiss();
}
loadingDialog = null;
isReadyToDismiss = false;
currentFlag = "";
lastFlag = "";
reqCount.set(0);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void dismiss(Object flag ) {
if (TextUtils.equals(currentFlag, flag.toString()) || currentFlag.isEmpty()) {
endReq();
}
}
//开始计数(可能多个请求)
private static void startReq() {
if (currentFlag.isEmpty()){
reqCount.set(1);
}else if (TextUtils.equals(currentFlag, lastFlag)){
reqCount.incrementAndGet();
}else {
reqCount.set(1);
}
}
//计数
private static void endReq() {
if (currentFlag.isEmpty()){
reqCount.set(0);
}else if (TextUtils.equals(currentFlag, lastFlag)){
reqCount.decrementAndGet();
}else {
reqCount.set(0);
}
//请求都结束了,去消失
if (reqCount.get() <= 0) {
reqCount.set(0);
loadNull();
}
}
/**
* 延时回收
*/
private static void loadNull() {
if (loadingDialog==null)return;
if (isReadyToDismiss) {
return;
}
isReadyToDismiss = true;
//500毫秒后结束,解决多个请求同时show和dismiss时dialog闪烁,
try {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (isReadyToDismiss && loadingDialog != null && reqCount.get() == 0) {
if (loadingDialog.isShowing()) {
loadingDialog.dismiss();
}
loadingDialog = null;
currentFlag = "";
lastFlag = "";
reqCount.set(0);
isReadyToDismiss = false;
}
}
},waitTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
有问题请留言。