使用协程在api请求之前从会议室数据库加载数据

问题描述 投票:0回答:2

我需要实现以下逻辑。当应用程序启动时,从共享的首选项中加载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,然后在存储库初始化时从数据库加载用户

@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)
        }
    }
}

拦截改装请求将令牌插入标头

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

android kotlin retrofit2 android-room kotlin-coroutines
2个回答
0
投票

为了确保已从db加载用户,可以在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()

0
投票

这是我目前的解决方案。感谢Marko Topolnik的想法。

在存储库中,我用自定义的初始化函数替换了init

fun init() {
    userId = sharedPrefs.getInt(PREFS_KEY_UID, 0)
    user = dao.geUser(userId)
}

并在MainActivity布局膨胀之前运行它并阻塞

override fun onCreate(savedInstanceState: Bundle?) {
    runBlocking(Dispatchers.IO) {
        App.userRepository.init()
    }
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    ...
}

该操作非常轻巧,因此不需要启动屏幕。

© www.soinside.com 2019 - 2024. All rights reserved.