我需要实现以下逻辑。当应用程序启动时,从共享的首选项中加载userId,然后从Room数据库中加载用户对象,以最终能够使用来自该用户对象的访问令牌发出翻新请求。
这就是我目前所在的位置。
在应用程序启动时使用Dagger初始化用户存储库
class App : Application() {
companion object {
lateinit var userRepository: UserRepository
}
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.factory().create(applicationContext)
userRepository = appComponent.userRepository()
}
}
从sharedPrefs加载userId
,然后在存储库初始化时从db加载用户
@Singleton
class UserRepository @Inject constructor(
private val dao: UserDao,
private val sharedPrefs: SharedPreferences
) {
var user: User
private var userId: Int
init {
userId = sharedPrefs.getInt(PREFS_KEY_UID, 0)
GlobalScope.launch(Dispatchers.IO) {
user = dao.geUser(userId)
}
}
}
Intercept Retrofit请求将令牌插入标头
interface Webservice {
companion object Factory {
private val headerInterceptor = Interceptor() {
val newRequest = it.request().newBuilder()
.addHeader("Authorization", "Bearer ${App.userRepository.user.token}")
.build()
it.proceed(newRequest)
}
fun create(): Webservice {
val client = OkHttpClient.Builder()
.addInterceptor(headerInterceptor)
.build();
val retrofit = retrofit2.Retrofit.Builder()
.client(client)
.baseUrl(BASE_URL)
.build()
return retrofit.create(Webservice::class.java)
}
}
}
创建MainActivity的ViewModel时发出第一个Web请求
class MainViewModel @Inject constructor(
private val repository: DataRepository
): ViewModel() {
val ticket: LiveData<Data> = repository.getData(viewModelScope)
}
@Singleton
class DataRepository @Inject constructor(
private val webservice: Webservice,
private val dao: DataDao
) {
fun getData(scope: CoroutineScope): LiveData<Data> {
refreshData(scope)
return dao.getData()
}
suspend fun refreshData(scope: CoroutineScope) {
scope.launch(Dispatchers.IO) {
...
val response = webservice.getData().awaitResponse()
...
dao.insert(response.body()!!)
...
}
}
}
您可能已经注意到我在使用协程。
在发送Web请求之前,如何确保从数据库中加载了user
?
答案 0 :(得分:0)
为确保已从数据库加载用户,可以将Deferred
与async
协程构建器一起使用,并在访问用户变量时调用await
函数。例如:
val user: Deferred<User>
init {
userId = sharedPrefs.getInt(PREFS_KEY_UID, 0)
user = GlobalScope.aync {
dao.geUser(userId)
}
}
....
val user = repository.user.await()
答案 1 :(得分:0)
这是我目前的解决方案。感谢Marko Topolnik的评论。
像这样用GlobalScope.launch
替换runBlocking
init {
userId = sharedPrefs.getInt(PREFS_KEY_UID, 0)
runBlocking(Dispatchers.IO) {
user = dao.geUser(userId)
}
}
在我看来,该操作重量轻,因此不需要启动屏幕。