Retrofitの接続先をSharedPreferenceに持つ場合
AndroidでHTTPで通信する場合、Retrofitを使う機会が多いと思います。
Retrofitの接続先のbaseUrlをSharedPreferenceに持つ場合があるともいます。
Androidアプリの中で設定画面を作って、SharedPreferenceのbaseUrlを更新しても、Retrofitの接続先には反映されません。
アプリを一度終了して、再度起動すると反映されます。
class NetworkRepository(baseUrl: String, connTimeout: Long, readTimeout: Long) {
private var service: NetworkService
/**
* 初期化
*/
init {
logging.setLevel(HttpLoggingInterceptor.Level.BASIC)
val client = OkHttpClient.Builder()
.readTimeout(connTimeout, TimeUnit.SECONDS)
.connectTimeout(readTimeout, TimeUnit.SECONDS)
.addInterceptor(logging)
.build()
service = Retrofit.Builder()
.baseUrl(baseUrl) // ★ ここが変わってくれない
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(NetworkService::class.java)
}
イマイチですね。
SharedPreferenceのbaseUrlを更新したら、即時にRetrofitの接続先には反映して欲しいですね。
SharedPreferences#registerOnSharedPreferenceChangeListener は何故かうまく動かない
SharedPreferences.OnSharedPreferenceChangeListenerを使うと、SharedPreferencesが何らか更新されたタイミングでlistenerを起動できると書かれていますが。
しかし、何故か公式ホームページの
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)
はうまく、動きませんでした。listenerが全く呼ばれません。
SharedPreferences.OnSharedPreferenceChangeListener を使う
SharedPreferences.OnSharedPreferenceChangeListener
をimplimentする方式だとうまく行きました。
MainActivityで、SharedPreferences.OnSharedPreferenceChangeListenerをimplimentして、onSharedPreferenceChangedを実装します。
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
・・・
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String?) {
if (key == "BASE_URL"
|| key == "CONN_TIMEOUT"
|| key == "READ_TIMEOUT") {
// baseURLまたはタイムアウトの変更
val baseUrl = preferences.getString("BASE_URL", "") ?: ""
val connectionTimeout = preferences.getString("CONN_TIMEOUT", "30")
val readTimeout = preferences.getString("READ_TIMEOUT", "30")
viewModel.networkRepository = NetworkRepository(baseUrl, connectionTimeout!!.toLong(), readTimeout!!.toLong())
}
}
・・・
override fun onResume() {
super.onResume()
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this)
}
SharedPreferencesのbaseUrlかコネクションタイムアウトか、リードタイムアウトのいずれかが変更されれば、NetworkRepository のインスタンスを作り直して、viewModelに再設定してやります。
AndroidのMVVMモデルだと、
Activity、またはFragment → viewModel → 各種repositoryの順に呼ばれますので、このような形になります。
上記の例はActivityにリスナを登録/解除する例で、同様にFragmentに対しても可能ですが、リスナを登録/解除するライフサイクルのタイミングが異なります。
・・・
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
PreferenceManager.getDefaultSharedPreferences(requireContext()).registerOnSharedPreferenceChangeListener(this)
}
・・・
override fun onDestroy() {
super.onDestroy()
PreferenceManager.getDefaultSharedPreferences(requireContext()).unregisterOnSharedPreferenceChangeListener(this)
}
・・・
Fragmentの場合はonCreate()、onDestroy()になります。