Android 多个请求时LoadingDialog反复显示消失问题的封装思考

场景

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();
        }
    }
}

有问题请留言。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值