SplashActivity.kt
@AndroidEntryPoint
@SuppressLint("CustomSplashScreen")
class SplashActivity : ComponentActivity() {
private val viewModel: SplashScreenViewModel by viewModels()
private val tokenManager = TokenManager(this)
val activity = this
private val errMsg = "Bir hata ile karşılaşıldı."
private fun navigateToMain(isTokenExist: Boolean) {
val intent = Intent(this@SplashActivity, MainActivity::class.java)
intent.putExtra("isTokenExist", isTokenExist)
startActivity(intent)
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { true }
}
super.onCreate(savedInstanceState)
if (viewModel.state.value.error) {
Toast.makeText(this@SplashActivity, errMsg, Toast.LENGTH_LONG).show()
}
lifecycleScope.launch(Dispatchers.IO) {
tokenManager.getRefreshToken().collect { refreshToken ->
if (refreshToken != null) {
if (viewModel.state.value.error) {
delay(2000)
activity.navigateToMain(false)
}
viewModel.state.collect {
activity.navigateToMain(!it.error)
}
activity.viewModel.refreshAccessToken(refreshToken) //unreachable code warning
} else {
delay(2000)
activity.navigateToMain(false)
}
}
}
}
}
SplashScreenViewModel.kt
@HiltViewModel
class SplashScreenViewModel @Inject constructor(
private val tokenManager: TokenManager
) : ViewModel() {
private val _state = MutableStateFlow(SplashScreenState())
val state: StateFlow<SplashScreenState> = _state.asStateFlow()
fun refreshAccessToken(refreshToken: String) {
viewModelScope.launch {
try {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
val okHttpClient = OkHttpClient
.Builder()
.addInterceptor(loggingInterceptor)
//.authenticator(AuthAuthenticator(tokenManager))
.build()
val retrofit = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
val service = retrofit.create(RegisterService::class.java)
val response = service.refreshToken(model = RefreshToken(refreshToken))
if (response.isSuccessful && response.body() != null) {
val newAccessToken = response.body()?.access_token
val newRefreshToken = response.body()?.refresh_token
if (newAccessToken != null && newRefreshToken != null) {
tokenManager.saveAccessToken(newAccessToken)
tokenManager.saveRefreshToken(newRefreshToken)
}
}
_state.update {
it.copy(
completed = true
)
}
} catch (e: Exception) {
_state.update {
it.copy(
error = true,
completed = true
)
}
}
}
}
}
data class SplashScreenState(
val error: Boolean = false,
var completed:Boolean = false
)
TokenManager.kt
class TokenManager(private val context: Context) {
companion object {
private val ACCESS_TOKEN = stringPreferencesKey("access_token")
private val REFRESH_TOKEN = stringPreferencesKey("refresh_token")
private val EXPIRATION_TIME = longPreferencesKey("expiration_time")
}
fun getAccessToken(): Flow<String?> {
return context.dataStore.data.map { preferences ->
preferences[ACCESS_TOKEN]
}
}
suspend fun saveAccessToken(token: String) {
context.dataStore.edit { preferences ->
preferences[ACCESS_TOKEN] = token
val expirationTime = System.currentTimeMillis()
preferences[EXPIRATION_TIME] = expirationTime + 86400 * 1000
}
}
fun getAccessTokenExpirationTime(): Flow<Long?> {
return context.dataStore.data.map { preferences ->
preferences[EXPIRATION_TIME]
}
}
suspend fun deleteAccessToken() {
context.dataStore.edit { preferences ->
preferences.remove(ACCESS_TOKEN)
}
}
fun getRefreshToken(): Flow<String?> {
return context.dataStore.data.map { preferences ->
preferences[REFRESH_TOKEN]
}
}
suspend fun saveRefreshToken(token: String) {
context.dataStore.edit { preferences ->
preferences[REFRESH_TOKEN] = token
val expirationTime = System.currentTimeMillis()
preferences[EXPIRATION_TIME] = expirationTime + 86400 * 1000
}
}
suspend fun deleteRefreshToken() {
context.dataStore.edit { preferences ->
preferences.remove(REFRESH_TOKEN)
}
}
我收到一个无法访问的代码警告。我在上面分享了我的飞溅活动和viewodel代码。我认为我做的代码是正确的,但有一部分我不喜欢,为什么android studio给出这个警告。
viewModel.state.collect {
activity.navigateToMain(!it.error)
}
activity.viewModel.refreshAccessToken(refreshToken) // --> Unreachable code warning
在这行代码中将activity.navigateToMain(!错误)
无论如何,当状态发生变化时不工作?
所以第一次没有任何变化,那么它就不会工作,下面的代码就会工作,所以**activity.viewModel.refreshAccessToken(refreshToken)对吗?
如果是这种情况,逻辑是正确的,但如果navigateToMain工作,那么第一次给予Unreachable code警告是正常的,因为导航后,它转到mainActivity,这终止了splashActivity,那么activity.viewModel.refreshAccessToken(refreshToken)**行不工作。我做的对吗?还是出了差错我不确定,所以我想问你能帮忙吗?
1条答案
按热度按时间m1m5dgzv1#
StateFlow永远不会完成,因此当您在
state
上调用collect
时,collect
调用下面的任何代码都不会到达,因为collect
永远不会返回。编辑:
按照您设置StateFlow的方式,当您准备导航时,它将具有
complete == true
值。因此,代码的快速简单修复方法是替换与
first
函数挂起,直到发出一个表示lambda中的条件的值,然后返回该值。另外,在这个
if (viewModel.state.value.error) {
块中,您可以导航离开屏幕,但随后允许逻辑的其余部分继续。您要么需要在这个if
块中调用return @launch
,要么将它下面的代码 Package 在else
块中。您还需要在调用
launch
后删除(Dispatchers.IO)
。在你的协程中没有需要它的阻塞代码,你需要在Main
上在活动之间导航。可选:这是我设计ViewModel类的方式,以避免在重新创建Fragment并再次调用
refreshAccessToken()
时冗余地重新启动fetch。