Android实战 -> 使用Interceptor+Lock实现无缝刷新Token

前言

哈喽各位我又来了,相信大家在做APP的时候肯定会遇到用户Token即将过期或者已经过期的情况,那么这个时候后端都返回相应的Code提示我们要求刷新Token处理。

那么今天这篇文章就给大家提供一个思路。

开工

技术点
  • Interceptor -> 拦截器
  • ReentrantLock -> 重入锁
实现思路
  • 通过TokenInterceptor获取Response解析请求结果验证是否Token过期
  • 监控到Token已过期后阻塞当前线程,调用刷新Token接口并使用Lock锁
  • 并发的请求也监控到了Token过期后,先校验Lock是否已锁,已锁等待,未锁步骤2
  • Token刷新成功后各线程携带新的Token创建Request重新请求

总结:4个并发线程接口,谁抢到了Lock锁谁去刷新Token,其他三个线程阻塞等待

实现代码
kotlin 复制代码
private fun handle(name: String) {
    Log.d(TAG, "handle 【Start】 called with: name = $name")
    try {
        if (!mLock.isLocked) {
            this.mLock.lock() // 加锁
            Log.d(TAG, "handle 【Start  Refresh】 called with: name = $name")
            Thread.sleep(5000) // 此处应为刷新Token请求
            Log.d(TAG, "handle 【End Refresh】 called with: name = $name")
            this.mLock.unlock() // 释放锁
        } else {
            Log.d(TAG, "handle 【Wait Refresh】 called with: name = $name")
            while (true) { // 阻塞等待
                if (!mLock.isLocked) { // 查询锁状态
                    Log.d(TAG, "handle 【OK Refresh】 called with: name = $name")
                    break
                }
            }
        }
    } finally {
        if (mLock.isLocked) {
            this.mLock.unlock()
        }
    }
    Log.d(TAG, "handle 【End】 called with: name = $name")
}

如上述代码,抢到Lock锁的线程去刷新Token,其余线程等待结果。

模拟测试
arduino 复制代码
// 此处模拟并发请求
this.findViewById<View>(R.id.btnGo).setOnClickListener {
    thread {
        handle("线程1")
    }
    thread {
        handle("线程2")
    }
    thread {
        handle("线程3")
    }
}
输出日志

如图,线程2抢到了Lock锁,线程1、3则进入了等待状态

如图,线程2刷新Token成功后释放了锁,线程1、3监听到了锁被释放则进入重新请求逻辑

完整代码
kotlin 复制代码
class MainAc : AppCompatActivity() {

    private val TAG = "zzz"

    private val mLock by lazy { ReentrantLock() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        super.setContentView(R.layout.ac_main)

        this.findViewById<View>(R.id.btnGo).setOnClickListener {
            thread {
                handle("线程1")
            }
            thread {
                handle("线程2")
            }
            thread {
                handle("线程3")
            }
        }
    }


    private fun handle(name: String) {
        Log.d(TAG, "handle 【Start】 called with: name = $name")
        try {
            if (!mLock.isLocked) {
                this.mLock.lock()
                Log.d(TAG, "handle 【Start  Refresh】 called with: name = $name")
                Thread.sleep(5000)
                Log.d(TAG, "handle 【End Refresh】 called with: name = $name")
                this.mLock.unlock()
            } else {
                Log.d(TAG, "handle 【Wait Refresh】 called with: name = $name")
                while (true) {
                    if (!mLock.isLocked) {
                        Log.d(TAG, "handle 【Go Refresh】 called with: name = $name")
                        break
                    }
                }
            }
        } finally {
            if (mLock.isLocked) {
                this.mLock.unlock()
            }
        }
        Log.d(TAG, "handle 【End】 called with: name = $name")
    }
}
End

到这里就结束了,简单吧,希望可以帮到在座的小伙伴们。当然如果有更好的实现方式或方案也希望各位在评论区留言讨论,我秒回复哦~ Bye

相关推荐
浏览器爱好者2 分钟前
如何在AWS上部署一个Web应用?
前端·云计算·aws
xiao-xiang18 分钟前
jenkins-通过api获取所有job及最新build信息
前端·servlet·jenkins
C语言魔术师34 分钟前
【小游戏篇】三子棋游戏
前端·算法·游戏
匹马夕阳2 小时前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?2 小时前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
水瓶丫头站住8 小时前
安卓APP如何适配不同的手机分辨率
android·智能手机
桂月二二8 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
xvch8 小时前
Kotlin 2.1.0 入门教程(五)
android·kotlin
hunter2062069 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb9 小时前
web服务器 网站部署的架构
服务器·前端·架构