前言
Jetpack Compose一般我们同时也会使用路由进行页面跳转,接口请求的时候,我们想用户信息失效的时候,退出到登录页面,直接在页面监听,就太麻烦和逻辑冗余了。
推荐的做法是
全局状态管理 + 统一网络拦截 + 导航控制
全局状态管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import androidx.compose.runtime.mutableStateOf
class AuthManager private constructor() { val isLoggedIn = mutableStateOf(true)
fun logout() { isLoggedIn.value = false }
fun login() { isLoggedIn.value = true }
companion object { @Volatile private var INSTANCE: AuthManager? = null
fun getInstance(): AuthManager { return INSTANCE ?: synchronized(this) { INSTANCE ?: AuthManager().also { INSTANCE = it } } } } }
|
网络拦截
接口拦截器中改变状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import android.os.Handler import android.os.Looper import android.util.Log import com.google.gson.Gson import com.xhkjedu.zxs_android.common.CommonData import com.xhkjedu.zxs_android.model.ResultVoNoData import com.xhkjedu.zxs_android.utils.common.ZSPUtil import okhttp3.Interceptor import okhttp3.Response import okhttp3.ResponseBody import okhttp3.ResponseBody.Companion.toResponseBody
class HeaderInterceptor : Interceptor { val TAG: String = "HeaderInterceptor"
override fun intercept(chain: Interceptor.Chain): Response { val original = chain.request() try { val mBuilder = original.newBuilder() if (CommonData.Authorization != "") { mBuilder.header("Authorization", CommonData.Authorization) }
val request = mBuilder .method(original.method, original.body) .build()
val response = chain.proceed(request) val headers = response.headers headers.forEach { header -> if (header.first.lowercase() == "authorization") { CommonData.Authorization = header.second ZSPUtil.putString("Authorization", header.second) Handler(Looper.getMainLooper()).post { AuthManager.getInstance().login() }
} }
return handleResponse(response) } catch (_: Exception) { return chain.proceed(original) } }
private fun handleResponse(response: Response): Response { val statusCode = response.code if (statusCode == 200) { val body = response.body body?.let { val contentType = it.contentType()?.toString() ?: "" if (contentType.contains("application/json")) { val responseStr = it.string() try { val resultVoNoData = Gson().fromJson( responseStr, ResultVoNoData::class.java ) if (resultVoNoData.code == 2) { Handler(Looper.getMainLooper()).post { AuthManager.getInstance().logout() } } } catch (_: Exception) { Log.e(TAG, "handleResponse: 解析失败") } val newBody: ResponseBody = responseStr .toResponseBody(it.contentType()) return response.newBuilder().body(newBody).build() } }
} return response } }
|
设置拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| if (!::commonRetrofit.isInitialized) { val client = getUnsafeOkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .addInterceptor(HeaderInterceptor()) .build();
commonRetrofit = Retrofit.Builder() .baseUrl(ConfigData.apiUrl) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() }
|
导航控制
路由配置中监听登录状态变化,退出登录。
通过监听状态,只有状态变化的时候才会退出登录,防止多次触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Composable fun AppNavigation() { val navController = rememberNavController()
val authManager = AuthManager.getInstance() val isLoggedIn by authManager.isLoggedIn LaunchedEffect(isLoggedIn) { if (!isLoggedIn) { navController.navigate(AppScreen.ScreenLogin.route) { popUpTo(navController.graph.startDestinationId) { inclusive = true } launchSingleTop = true } } }
CompositionLocalProvider(LocalNavController provides navController) { NavHost( navController = navController, startDestination = "root", enterTransition = { slideIntoContainer( AnimatedContentTransitionScope.SlideDirection.Left ) }, exitTransition = { slideOutOfContainer( AnimatedContentTransitionScope.SlideDirection.Right ) } ) { rootNavGraph(navController) } } }
|
核心代码
1 2 3 4 5 6 7 8 9 10 11
| val authManager = AuthManager.getInstance() val isLoggedIn by authManager.isLoggedIn
LaunchedEffect(isLoggedIn) { if (!isLoggedIn) { navController.navigate(AppScreen.ScreenLogin.route) { popUpTo(navController.graph.startDestinationId) { inclusive = true } launchSingleTop = true } } }
|