0
0
Android強化月間 - Androidアプリ開発の知見を共有しよう -

AndroidでRtrofitの接続先をSharedPreferencesに持つ場合

Last updated at Posted at 2023-09-14

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を実装します。

MainActivity.kt
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()になります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0