使用Hilt注入PreferenceFile到TokenAuthenticator时出现未初始化错误的求助
Hey there! Let's figure out why you're getting that "lateinit property preferenceFile has not been initialized" error. The main issues are with how you're handling injection in your TokenAuthenticator and a small mistake in your PreferenceFile setup. Here's how to fix it step by step:
1. Fix TokenAuthenticator to use Constructor Injection
Right now, you're using field injection (@Inject on the properties) in a class that already has an @Inject constructor(). For regular non-Android classes like TokenAuthenticator, Hilt relies on constructor injection to pass dependencies—field injection won't work here because Hilt doesn't automatically inject fields for these classes.
Update your TokenAuthenticator to take dependencies directly in the constructor:
class TokenAuthenticator @Inject constructor( private val retrofitApi: RetrofitApi, private val preferenceFile: PreferenceFile ) : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { val refreshTokenIs = preferenceFile.retrieveKey(refreshToken) val responseRefresh = retrofitApi.refreshToken(refreshTokenIs ?: "") return if (responseRefresh.isSuccessful) { val newAccessToken = responseRefresh.body() preferenceFile.storeKey(token, newAccessToken?.token ?: "") preferenceFile.storeKey(refreshToken, newAccessToken?.refreshToken ?: "") preferenceFile.storeKey(tokenType, newAccessToken?.type ?: "") response.request.newBuilder() .header(AUTH_PARAM, "${newAccessToken?.type} ${newAccessToken?.token}") .build() } else { Log.e("sessionExpired", "===sessionExpired") MainActivity.context.get()?.sessionExpired() null } } }
2. Fix PreferenceFile to Avoid Singleton Editor
Your current setup injects a singleton SharedPreferences.Editor, which is incorrect. Editors are meant to be created per edit operation—reusing a single editor instance can lead to unexpected behavior (like unsaved changes) after you call apply() or commit().
Update your PreferenceFile to create a new editor each time you need to modify preferences:
class PreferenceFile @Inject constructor( val sharedPreferences: SharedPreferences ) { fun storeKey(key: String, value: String) { sharedPreferences.edit() .putString(key, value) .apply() } fun storeBoolKey(key: String, value: Boolean) { sharedPreferences.edit() .putBoolean(key, value) .apply() } fun retrieveKey(key: String): String? { return sharedPreferences.getString(key, null) } fun retrieveBoolKey(key: String): Boolean { return sharedPreferences.getBoolean(key, false) } fun <T> storeObject(key: String, data: T) { val jsonString = GsonBuilder().create().toJson(data) sharedPreferences.edit() .putString(key, jsonString) .apply() } inline fun <reified T> getStoreObject(key: String): T? { val json = sharedPreferences.getString(key, null) return GsonBuilder().create().fromJson(json, T::class.java) } fun clearPreference() { sharedPreferences.edit() .clear() .apply() } }
3. Simplify Your PrefModule
Since we no longer inject the SharedPreferences.Editor, you can remove that provider from your module. Keep only the SharedPreferences provider:
@InstallIn(SingletonComponent::class) @Module class PrefModule { @Provides @Singleton fun getPref(@ApplicationContext context: Context): SharedPreferences = context.getSharedPreferences(preferenceName, Context.MODE_PRIVATE) }
4. Quick Checks to Ensure Everything Works
- Make sure your
RetrofitApiis properly provided in a Hilt module (e.g., viaRetrofit.create(RetrofitApi::class.java)). - Verify that your
OkHttpClientis created using Hilt, with theTokenAuthenticatorinjected into it:@Provides @Singleton fun provideOkHttpClient(tokenAuthenticator: TokenAuthenticator): OkHttpClient { return OkHttpClient.Builder() .authenticator(tokenAuthenticator) // Add other configs like interceptors or timeouts here .build() } - Ensure your app class is annotated with
@HiltAndroidApp(required for Hilt to initialize):@HiltAndroidApp class MyApp : Application() { }
These changes should resolve the lateinit error because Hilt will now properly inject PreferenceFile and RetrofitApi into TokenAuthenticator via its constructor, and your preference operations will use the correct editor instances.
备注:内容来源于stack exchange,提问作者Suraj Bahadur

