rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

android開発 LiveDataの利用パターン

2021 Sep. 03.

ViewModelクラス内でLiveDataを設定する

 各LiveData対象について、書き換え可能なMutableLiveDataと読み込み専用のLiveDataの2つの変数を作る。

  private val _FOO: MutableLiveData by lazy { MutableLiveData() }
  val FOO: LiveData
   get() = _FOO

 値のセットは、MutableLiveData#postValue(HOGE)を使う。


MainActivity内で読み込み専用のLiveDataを読み込む

 Observerを作る。
 LiveData#observe()で読み込む。


サンプル
SmbViewModel.kt

class SmbViewModel(): ViewModel() {

    // LiveDataを設定する
    private val _smbPath: MutableLiveData<String> by lazy {
        // MutableLiveData<T>は、valでmutableな変数を宣言できる
        MutableLiveData<String>()
    }
    val smbPath: LiveData<String>
        // 下記により、smbPathの読み込み時は _smbPathが読み出される
        get() = _smbPath

    private val _smbSize: MutableLiveData<Long> by lazy {
        MutableLiveData<Long>()
    }
    val smbSize: LiveData<Long>
        get() = _smbSize

    private val _isConnectedSmb = MutableLiveData<Boolean>()
    val isConnectedSmb: LiveData<Boolean>
        get() = _isConnectedSmb

    // SMBサーバーへの接続
    fun connectSmb() {
        viewModelScope.launch(Dispatchers.IO) {
            val prop = Properties()  // java.util.Properties
            prop.setProperty("jcifs.smb.client.minVersion", "SMB202")
            prop.setProperty("jcifs.smb.client.maxVersion", "SMB300")
            val baseCxt = BaseContext(PropertyConfiguration(prop))
            val auth =
                baseCxt.withCredentials(NtlmPasswordAuthenticator(domain, user, password))
            val smb = SmbFile(smbUrl, auth)
            if (smb.exists()) {
                // LiveDataにSMBサーバーからのデータをセットする
                //   ワーカースレッド空間のデータをLiveDataにセットするにはpostValue()を使う
                _smbPath.postValue(smb.path)
                _smbSize.postValue(smb.length())
                _isConnectedSmb.postValue(true)
            } else {
                _isConnectedSmb.postValue(false)
            }
        }
    }
}


MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // get ViewModel for SmbConnection
        val smbViewModelFactory = SmbViewModelFactory(USER, PASSWORD, DOMAIN, smbUrl)
        val smbViewModel: SmbViewModel = ViewModelProvider(this, smbViewModelFactory).get(SmbViewModel::class.java)

        // connect SMB server
        smbViewModel.connectSmb()

        // check if SMB-connection succeeded
        val isConnectedObserver = Observer<Boolean> { isConnected ->
            if (!isConnected) {
                finishAndRemoveTask()
            }
        }
        smbViewModel.isConnectedSmb.observe(this,isConnectedObserver)

        /*
         * get data in SMB server
         *     参考ページ https://developer.android.com/topic/libraries/architecture/livedata?hl=ja
         */
        // Create the observer which updates the UI.
        val pathObserver = Observer<String> { sPath ->
            // Update the UI
            binding.tvSmbPath.text = sPath
        }
        val sizeObserver = Observer<Long> { sSize ->
            // Update the UI
            binding.tvSmbSize.text = sSize.toString()
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        //   observe(Owner, ...)のOwnerは、Activityの時はthis、Fragmentの時はviewLifecycleOwnerとする
        smbViewModel.smbPath.observe(this, pathObserver)
        smbViewModel.smbSize.observe(this, sizeObserver)

        // 上記のようにObserverインスタンスの生成はせず、下記のようにまてめてもよい
        /*
        smbViewModel._smbPath.observe(this, Observer { sPath -> binding.tvSmbPath.setText(sPath) })
        smbViewModel._smbSize.observe(this, Observer { sSize -> binding.tvSmbSize.setText(sSize.toString()) })
        */
    }
}