{"id":175,"date":"2021-08-19T16:35:47","date_gmt":"2021-08-19T07:35:47","guid":{"rendered":"https:\/\/www.avancesys.co.jp\/laboratory\/?post_type=article&#038;p=175"},"modified":"2021-09-08T13:38:02","modified_gmt":"2021-09-08T04:38:02","slug":"%e7%ac%ac3%e5%9b%9e-%e9%a1%94%e8%aa%8d%e8%ad%98%e3%83%87%e3%83%90%e3%82%a4%e3%82%b9-android%e7%b7%a8-%e3%80%9c-livedata%e3%81%a8databinding%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b-%e3%80%9c","status":"publish","type":"article","link":"https:\/\/www.avancesys.co.jp\/laboratory\/article\/%e7%ac%ac3%e5%9b%9e-%e9%a1%94%e8%aa%8d%e8%ad%98%e3%83%87%e3%83%90%e3%82%a4%e3%82%b9-android%e7%b7%a8-%e3%80%9c-livedata%e3%81%a8databinding%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b-%e3%80%9c\/","title":{"rendered":"\u7b2c3\u56de \u9854\u8a8d\u8b58\u30c7\u30d0\u30a4\u30b9 Android\u7de8 \u301c LiveData\u3068DataBinding\u3092\u5b9f\u88c5\u3059\u308b \u301c"},"content":{"rendered":"\n<p>\u524d\u56de\u306b\u5f15\u304d\u7d9a\u304d\u3001MVVM\u306e\u5b9f\u88c5\u3092\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p>ViewModel\u306e\u5b9f\u88c5\u3067\u306f\u3001UI\u306e\u72b6\u614b\u7ba1\u7406\u3084\u30ed\u30b8\u30c3\u30af\u306e\u5206\u96e2\u3092\u5b9f\u65bd\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u4eca\u56de\u306f<mark id=\"keyword\">LiveData<\/mark>\u3092\u4f7f\u7528\u3057\u3066\u3001Bluetooth\u30c7\u30d0\u30a4\u30b9\u3068\u306e\u63a5\u7d9a\u72b6\u614b\u306e\u5909\u5316\u3092\u76e3\u8996\u3057\u3064\u3064\u9069\u5207\u306a\u30bf\u30a4\u30df\u30f3\u30b0\u3067\u81ea\u52d5\u66f4\u65b0\u3059\u308b\u5b9f\u88c5\u3068\u3001<\/p>\n\n\n\n<p><mark id=\"keyword\">DataBinding<\/mark>\u3092\u4f7f\u7528\u3057\u3066\u30ec\u30a4\u30a2\u30a6\u30c8\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u305d\u306e\u72b6\u614b\u5909\u5316\u3092UI\u3078\u66f4\u65b0\u3067\u304d\u308b\u3088\u3046\u306b\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u524d\u56de\uff1a<a href=\"https:\/\/www.avancesys.co.jp\/laboratory\/article\/%e7%ac%ac2%e5%9b%9e-%e9%a1%94%e8%aa%8d%e8%ad%98%e3%83%87%e3%83%90%e3%82%a4%e3%82%b9-android%e7%b7%a8-%e3%80%9c-jetpack%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6viewmodel%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99\/\" data-type=\"URL\" data-id=\"https:\/\/www.avancesys.co.jp\/laboratory\/article\/%e7%ac%ac2%e5%9b%9e-%e9%a1%94%e8%aa%8d%e8%ad%98%e3%83%87%e3%83%90%e3%82%a4%e3%82%b9-android%e7%b7%a8-%e3%80%9c-jetpack%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6viewmodel%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99\/\">Android\u7de8 JetPack\u3092\u4f7f\u3063\u3066ViewModel\u3092\u5b9f\u88c5\u3059\u308b<\/a><\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-pullquote\" style=\"border-color:#0693e3\"><blockquote><p>1. \u6e96\u5099<\/p><\/blockquote><\/figure>\n\n\n\n<p>LiveData\u3001DataBinding \u3092\u4f7f\u7528\u3059\u308b\u305f\u3081\u306b\u5fc5\u8981\u306a\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p><strong>buid.gradle(app)<\/strong><\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-swift\" data-lang=\"Swift\" data-show-lang=\"0\"><code>apply plugin: &#39;com.android.application&#39;\napply plugin: &#39;kotlin-android&#39;\napply plugin: &#39;kotlin-android-extensions&#39;\napply plugin: &#39;kotlin-kapt&#39;\n\nandroid {\n    ...\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    \/\/ \u8ffd\u52a0\n    dataBinding {\n        enabled = true\n    }\n\n    kotlinOptions {\n        jvmTarget = &#39;1.8&#39;\n    }\n\n    dependencies {\n        ...\n        \/\/ lifecycle\n        implementation &quot;androidx.lifecycle:lifecycle-extensions:$lifecycle_version&quot;\n        implementation &quot;androidx.lifecycle:lifecycle-common-java8:$lifecycle_version&quot;\n        implementation &quot;androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version&quot;\n        implementation &quot;androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version&quot;   \/\/ \u8ffd\u52a0\n\n        \/\/ coroutine\n        implementation &quot;org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version&quot;\n        implementation &quot;org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version&quot;\n    }\n}<\/code><\/pre><\/div>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-pullquote\" style=\"border-color:#0693e3\"><blockquote><p>2. LiveData\u306e\u5b9f\u88c5<\/p><\/blockquote><\/figure>\n\n\n\n<p>\u524d\u56de\u4f5c\u6210\u3057\u305f\u3001ConnectViewModel\u3078\u4e0b\u8a18\u72b6\u614b\u3092\u8868\u3059<mark id=\"keyword\">LiveData<\/mark>\u3092\u5b9f\u88c5\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Bluetooth \u63a5\u7d9a\u72b6\u614b\uff08sppConnectStatus\uff09<\/li><li>\u63a5\u7d9a\u30dc\u30bf\u30f3\u306e Enabled \u72b6\u614b\uff08connectButtonEnabled\uff09<\/li><li>\u5207\u65ad\u30dc\u30bf\u30f3\u306e Enabled \u72b6\u614b\uff08disconnectButtonEnabled\uff09<\/li><\/ul>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u307e\u305f\u3001Activity \u3067\u7d99\u627f\u3057\u3066\u3044\u305f<mark id=\"keyword\">ISppClient<\/mark>\uff08SPP\u901a\u4fe1\u306e\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\uff09\u306fViewModel\u306b\u7d99\u627f\u3055\u305b\u307e\u3059\u3002<\/p>\n\n\n\n<p><mark id=\"keyword\">SppConnectStatus<\/mark>\u306f\u901a\u4fe1\u72b6\u614b\u3092\u7ba1\u7406\u3059\u308b\u305f\u3081\u306b\u5b9a\u7fa9\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p><strong>ConnectionViewModel.kt<\/strong><\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-swift\" data-lang=\"Swift\" data-show-lang=\"0\"><code>class ConnectViewModel(val app: Application) : AndroidViewModel(app), ISppClient {\n\n    ...\n\n    \/\/ liveData\n    private val mSppConnectStatus = MutableLiveData&lt;SppConnectStatus&gt;()\n    private val mConnectButtonEnabled = MutableLiveData&lt;Boolean&gt;()\n    private val mDisconnectButtonEnabled = MutableLiveData&lt;Boolean&gt;()\n\n    val sppConnectStatus: LiveData&lt;SppConnectStatus&gt; get() = mSppConnectStatus\n    val connectButtonEnabled: LiveData&lt;Boolean&gt; get() = mConnectButtonEnabled\n    val disconnectButtonEnabled: LiveData&lt;Boolean&gt; get() = mDisconnectButtonEnabled\n\n    \/**\n     * Bluetooth\u30c7\u30d0\u30a4\u30b9\u3068\u306e\u63a5\u7d9a\u72b6\u614b\n     *\/\n    enum class SppConnectStatus {\n        CONNECTED {\n            override fun toast(context: Context) {\n                Toast.makeText(context, &quot;\u63a5\u7d9a\u6210\u529f&quot;, Toast.LENGTH_SHORT).show()\n            }\n        },\n        CONNECT_ERROR {\n            override fun toast(context: Context) {\n                Toast.makeText(context, &quot;\u63a5\u7d9a\u5931\u6557&quot;, Toast.LENGTH_SHORT).show()\n            }\n        },\n        DISCONNECTED {\n            override fun toast(context: Context) {\n                Toast.makeText(context, &quot;\u63a5\u7d9a\u5207\u65ad&quot;, Toast.LENGTH_SHORT).show()\n            }\n        },\n        NOT_CONNECTION {\n            override fun toast(context: Context) {}\n        };\n\n        abstract fun toast(context: Context)\n    }\n\n    init {\n        deviceAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item)\n        mSppConnectStatus.value = SppConnectStatus.NOT_CONNECTION\n        mConnectButtonEnabled.value = false\n        mDisconnectButtonEnabled.value = false\n\n        \/\/ SPP\u901a\u4fe1\u306e\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n        MyApplication.instance.sppClient.addListener(this)\n    }\n\n    ...\n\n    fun updateButtonState() {\n        if (MyApplication.instance.sppClient.isConnected()) {\n            mConnectButtonEnabled.postValue(false)\n            mDisconnectButtonEnabled.postValue(true)\n        } else {\n            mConnectButtonEnabled.postValue(btDevice != null)\n            mDisconnectButtonEnabled.postValue(false)\n        }\n    }\n\n    \/\/ ISppClient method\n    override fun onConnected(result: Boolean) {\n        viewModelScope.launch {\n            if (result) {\n                \/\/ \u63a5\u7d9a\u6210\u529f\n                mSppConnectStatus.postValue(SppConnectStatus.CONNECTED)\n            } else {\n                \/\/ \u63a5\u7d9a\u5931\u6557\n                mSppConnectStatus.postValue(SppConnectStatus.CONNECT_ERROR)\n            }\n\n            updateButtonState()\n        }\n    }\n\n    \/\/ ISppClient method\n    override fun onDisconnected() {\n        viewModelScope.launch {\n            \/\/ \u63a5\u7d9a\u5207\u65ad\n            mSppConnectStatus.postValue(SppConnectStatus.DISCONNECTED)\n            updateButtonState()\n            \/\/ 300msec \u306e\u9045\u5ef6\u3092\u633f\u5165\u5f8c\u3001\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u623b\u3059\n            delay(300)\n            mSppConnectStatus.postValue(SppConnectStatus.NOT_CONNECTION)\n        }\n    }\n}<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">2.1 \u521d\u671f\u5316<\/h2>\n\n\n\n<p>\u307e\u305a\u306f\u3001LiveData\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u5ba3\u8a00\u3068\u521d\u671f\u5316\u3067\u3059\u3002<\/p>\n\n\n\n<p>\u5916\u90e8\u304b\u3089\u53c2\u7167\u3059\u308b\u3068\u304d\u306f\u3001\u30a4\u30df\u30e5\u30fc\u30bf\u30d6\u30eb\u578b\u306b\u3057\u3066\u3044\u307e\u3059\u304c\u3001\u3053\u306e\u3042\u305f\u308a\u306f\u304a\u597d\u307f\u3067\u3059\u3002<\/p>\n\n\n\n<p>\u5024\u306e\u5909\u66f4\u306f\u3001<mark id=\"keyword\">value<\/mark>\u306b\u4ee3\u5165\u3059\u308b\u304b\u3001<mark id=\"keyword\">postValue()<\/mark>\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3069\u3061\u3089\u3082\u610f\u5473\u5408\u3044\u306f\u540c\u3058\u3067\u3059\u304c\u3001<mark id=\"keyword\">value<\/mark>\u306f\u30e1\u30a4\u30f3\u30b9\u30ec\u30c3\u30c9\u304b\u3089\u5b9f\u884c\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u3001<\/p>\n\n\n\n<p><mark id=\"keyword\">postValue()<\/mark>\u306f\u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u304b\u3089\u5b9f\u884c\u3057\u3066\u3082\u30e1\u30a4\u30f3\u30b9\u30ec\u30c3\u30c9\u3078\u6700\u65b0\u5024\u304c\u30c7\u30a3\u30b9\u30d1\u30c3\u30c1\u3055\u308c\u308b\u3088\u3046\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2.2 \u30dc\u30bf\u30f3\u306e\u72b6\u614b\u7ba1\u7406<\/h2>\n\n\n\n<p>\u65e2\u5b58\u30b3\u30fc\u30c9\u3067\u306f\u30dc\u30bf\u30f3\u306e Enabled \u3092\u76f4\u63a5\u64cd\u4f5c\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5f8c\u8ff0\u3059\u308b<mark id=\"keyword\">DataBinding<\/mark>\u3067 UI\u64cd\u4f5c\u3092Activity\u304b\u3089\u5206\u96e2\u3059\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p><mark id=\"keyword\">postValue()<\/mark>\u3092\u4f7f\u7528\u3057\u3066\u30dc\u30bf\u30f3\u306e\u6700\u65b0\u72b6\u614b\u3092View\u3078\u53cd\u6620\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-swift\" data-lang=\"Swift\" data-show-lang=\"0\"><code>    fun updateButtonState() {\n        if (MyApplication.instance.sppClient.isConnected()) {\n            mConnectButtonEnabled.postValue(false)\n            mDisconnectButtonEnabled.postValue(true)\n        } else {\n            mConnectButtonEnabled.postValue(btDevice != null)\n            mDisconnectButtonEnabled.postValue(false)\n        }\n    }<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">2.3 Bluetooth\u901a\u4fe1\u306e\u72b6\u614b\u7ba1\u7406<\/h2>\n\n\n\n<p>\u63a5\u7d9a\u6210\u529f\u3001\u63a5\u7d9a\u5931\u6557\u3001\u63a5\u7d9a\u5207\u65ad\u306e\u901a\u4fe1\u72b6\u614b\u3092\u76e3\u8996\u3057\u3001\u72b6\u614b\u66f4\u65b0\u306b\u5408\u308f\u305b\u3066\u30c8\u30fc\u30b9\u30c8\u3092\u8868\u793a\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-swift\" data-lang=\"Swift\" data-show-lang=\"0\"><code>    \/\/ ISppClient method\n    override fun onConnected(result: Boolean) {\n        viewModelScope.launch {\n            if (result) {\n                \/\/ \u63a5\u7d9a\u6210\u529f\n                mSppConnectStatus.postValue(SppConnectStatus.CONNECTED)\n            } else {\n                \/\/ \u63a5\u7d9a\u5931\u6557\n                mSppConnectStatus.postValue(SppConnectStatus.CONNECT_ERROR)\n            }\n\n            updateButtonState()\n        }\n    }\n\n    \/\/ ISppClient method\n    override fun onDisconnected() {\n        viewModelScope.launch {\n            \/\/ \u63a5\u7d9a\u5207\u65ad\n            mSppConnectStatus.postValue(SppConnectStatus.DISCONNECTED)\n            updateButtonState()\n            \/\/ 300msec \u306e\u9045\u5ef6\u3092\u633f\u5165\u5f8c\u3001\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u623b\u3059\n            delay(300)\n            mSppConnectStatus.postValue(SppConnectStatus.NOT_CONNECTION)\n        }\n    }<\/code><\/pre><\/div>\n\n\n\n<p>LiveData\u306e\u5024\u5909\u66f4\u306f<mark id=\"keyword\">observe()<\/mark>\u3067\u76e3\u8996\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p><strong>ConnectActivity.kt<\/strong><\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-swift\" data-lang=\"Swift\" data-show-lang=\"0\"><code>    ...\n    \n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_connect)\n\n        ...\n\n        \/\/ liveData observer\n        viewModel.sppConnectStatus.observe(this, Observer { connectStatus -&gt;\n            connectStatus.toast(this)\n        })\n    }<\/code><\/pre><\/div>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-pullquote\" style=\"border-color:#0693e3\"><blockquote><p>3. DataBinding\u306e\u5b9f\u88c5<\/p><\/blockquote><\/figure>\n\n\n\n<p>DataBinding\u306f\u30ec\u30a4\u30a2\u30a6\u30c8\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u6307\u5b9a\u3057\u305f\u30af\u30e9\u30b9\u306e\u5909\u6570\u3084\u30e1\u30bd\u30c3\u30c9\u3092\u53c2\u7167\u3059\u308b\u3053\u3068\u304c\u51fa\u6765\u307e\u3059\u3002\u3053\u308c\u306b\u3088\u308a\u3001Activity\u3084Fragment\u304b\u3089UI\u64cd\u4f5c\u3092\u5206\u96e2\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u4eca\u56de\u306f\u3001\u30dc\u30bf\u30f3\u306e \u6709\u52b9\/\u7121\u52b9 \u3068 \u30af\u30ea\u30c3\u30af\u30a4\u30d9\u30f3\u30c8 \u3092\u7d10\u4ed8\u3051\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3.1 \u30ec\u30a4\u30a2\u30a6\u30c8\u30d5\u30a1\u30a4\u30eb\u306e\u4fee\u6b63<\/h2>\n\n\n\n<p>\u30ec\u30a4\u30a2\u30a6\u30c8\u30d5\u30a1\u30a4\u30eb\u304b\u3089ViewModel\u3092\u53c2\u7167\u3059\u308b\u306b\u306f\u30eb\u30fc\u30c8\u968e\u5c64\u3092<mark id=\"keyword\">&lt;layout&gt; &#8230; &lt;\/layout&gt;<\/mark>\u3067\u56f2\u3080\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u30eb\u30fc\u30c8\u968e\u5c64\u3092\u53f3\u30af\u30ea\u30c3\u30af\u3057\u3066\u3001[Show Context Actions] \u2192 [Convert to data binding layout] \u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u81ea\u52d5\u5909\u63db\u3057\u3066\u304f\u308c\u307e\u3059\u3002\u4fbf\u5229\u3067\u3059\uff01<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"643\" height=\"116\" src=\"https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/08\/dataBinding_layout.png\" alt=\"\" class=\"wp-image-181\" srcset=\"https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/08\/dataBinding_layout.png 643w, https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/08\/dataBinding_layout-300x54.png 300w\" sizes=\"auto, (max-width: 643px) 100vw, 643px\" \/><\/figure>\n\n\n\n<p><strong>activity_connect.xml<\/strong><\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-html\" data-lang=\"HTML\" data-show-lang=\"0\"><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\n&lt;layout xmlns:android=&quot;http:\/\/schemas.android.com\/apk\/res\/android&quot;\n    xmlns:app=&quot;http:\/\/schemas.android.com\/apk\/res-auto&quot;\n    xmlns:tools=&quot;http:\/\/schemas.android.com\/tools&quot;&gt;\n\n    &lt;data&gt;\n        &lt;variable\n            name=&quot;viewModel&quot;\n            type=&quot;jp.co.avancesys.sample.demo001.view.screen.connect.ConnectViewModel&quot; \/&gt;\n    &lt;\/data&gt;\n\n    &lt;androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=&quot;match_parent&quot;\n        android:layout_height=&quot;match_parent&quot;\n        android:background=&quot;@color\/app_background&quot;\n        tools:context=&quot;.view.screen.connect.ConnectActivity&quot;&gt;\n\n        &lt;LinearLayout\n            android:layout_width=&quot;match_parent&quot;\n            android:layout_height=&quot;wrap_content&quot;\n            android:orientation=&quot;vertical&quot;\n            android:padding=&quot;8dp&quot;\n            app:layout_constraintEnd_toEndOf=&quot;parent&quot;\n            app:layout_constraintStart_toStartOf=&quot;parent&quot;\n            app:layout_constraintTop_toTopOf=&quot;parent&quot;&gt;\n\n            &lt;LinearLayout\n                android:layout_width=&quot;match_parent&quot;\n                android:layout_height=&quot;wrap_content&quot;\n                android:orientation=&quot;horizontal&quot;&gt;\n\n                &lt;Spinner\n                    android:id=&quot;@+id\/spinnerDevices&quot;\n                    android:layout_width=&quot;0dp&quot;\n                    android:layout_height=&quot;wrap_content&quot;\n                    android:layout_gravity=&quot;center_vertical&quot;\n                    android:layout_margin=&quot;8dp&quot;\n                    android:layout_weight=&quot;1&quot;\n                    android:backgroundTint=&quot;#FFFFFF&quot; \/&gt;\n\n                &lt;Button\n                    android:id=&quot;@+id\/buttonConnect&quot;\n                    android:layout_width=&quot;wrap_content&quot;\n                    android:layout_height=&quot;wrap_content&quot;\n                    android:text=&quot;connect&quot;\n                    android:enabled=&quot;@{viewModel.connectButtonEnabled}&quot;\n                    android:onClick=&quot;@{(v) -&gt; viewModel.connectBtDevice()}&quot;\/&gt;\n\n                &lt;Button\n                    android:id=&quot;@+id\/buttonDisconnect&quot;\n                    android:layout_width=&quot;wrap_content&quot;\n                    android:layout_height=&quot;wrap_content&quot;\n                    android:text=&quot;disconnect&quot;\n                    android:enabled=&quot;@{viewModel.disconnectButtonEnabled}&quot;\n                    android:onClick=&quot;@{(v) -&gt; viewModel.disconnectBtDevice()}&quot;\/&gt;\n\n            &lt;\/LinearLayout&gt;\n\n        &lt;\/LinearLayout&gt;\n\n    &lt;\/androidx.constraintlayout.widget.ConstraintLayout&gt;\n&lt;\/layout&gt;<\/code><\/pre><\/div>\n\n\n\n<p><mark id=\"keyword\">&lt;data&gt; &#8230; &lt;\/data&gt;<\/mark>\u3067\u56f2\u307e\u308c\u305f\u7b87\u6240\u304c\u53c2\u7167\u3059\u308bViewModel\u3068\u306a\u308a\u3001\u547c\u3073\u51fa\u3057\u306f<mark id=\"keyword\">@{}<\/mark>\u3067\u56f2\u307f\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u3053\u3067\u306f\u3001\u5148\u7a0bLiveData\u3067\u5b9a\u7fa9\u3057\u305f\u63a5\u7d9a\u30dc\u30bf\u30f3\u3068\u5207\u65ad\u30dc\u30bf\u30f3\u306e\u72b6\u614b\u5909\u6570\u3092<mark id=\"keyword\">android:enabled=<\/mark>\u3078\u3001\u30dc\u30bf\u30f3\u3092\u30bf\u30c3\u30d7\u3057\u305f\u3068\u304d\u306e\u5185\u90e8\u51e6\u7406\u3092<mark id=\"keyword\">android:onClick=<\/mark>\u3078\u30d0\u30a4\u30f3\u30c9\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"> 3.2 Activity\u306e\u4fee\u6b63 <\/h2>\n\n\n\n<p>\u305d\u308c\u3067\u306f\u3001\u4ed5\u4e0a\u3052\u306bActivity\u3092\u4fee\u6b63\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u307e\u305a\u3001<mark id=\"keyword\">DataBindingUtil.setContentView&lt;T&gt;()<\/mark>\u3067DataBinding\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u53d6\u5f97\u3057\u307e\u3059\u3002T\u306b\u6307\u5b9a\u3057\u3066\u3044\u308b<mark id=\"keyword\">ActivityConnectBinding<\/mark>\u306f\u81ea\u52d5\u751f\u6210\u3067\u3059\u3002<\/p>\n\n\n\n<p>\u6b21\u306b\u3001<mark id=\"keyword\">binding.viewModel<\/mark>\u3068<mark id=\"keyword\">binding.lifecycleOwner<\/mark>\u3092\u7d10\u4ed8\u3051\u305f\u3089\u5b8c\u4e86\u3067\u3059\uff01<\/p>\n\n\n\n<p>\u3069\u3046\u3067\u3057\u3087\u3046\u3002Activity\u5185\u306e\u51e6\u7406\u304c\u307b\u3068\u3093\u3069\u306a\u304f\u306a\u308a\u30b9\u30c3\u30ad\u30ea\u3057\u305f\u6c17\u304c\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p><strong>ConnectActivity.kt<\/strong><\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-swift\" data-lang=\"Swift\" data-show-lang=\"0\"><code>class ConnectActivity : BaseActivity() {\n\n    private val viewModel: ConnectViewModel by lazy {\n        val factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application)\n        ViewModelProvider(this, factory).get(ConnectViewModel::class.java)\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_connect)\n\n        val binding = DataBindingUtil.setContentView&lt;ActivityConnectBinding&gt;(this, R.layout.activity_connect)\n        binding.viewModel = viewModel\n        binding.lifecycleOwner = this\n\n        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n\n        \/\/ \u30b9\u30d4\u30ca\u30fc\n        binding.spinnerDevices.adapter = viewModel.deviceAdapter\n        binding.spinnerDevices.onItemSelectedListener = viewModel.spinnerOnItemSelectedListener\n\n        \/\/ liveData observer\n        viewModel.sppConnectStatus.observe(this, Observer { connectStatus -&gt;\n            connectStatus.toast(this)\n        })\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        \/\/ \u30b9\u30d4\u30ca\u30fc\u306e\u5185\u5bb9\u3092\u66f4\u65b0\n        viewModel.updateSpinner { selectIndex -&gt;\n            spinnerDevices.setSelection(selectIndex, false)\n        }\n\n        viewModel.updateButtonState()\n    }\n}<\/code><\/pre><\/div>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-pullquote\" style=\"border-color:#0693e3\"><blockquote><p>\u6700\u5f8c\u306b<\/p><\/blockquote><\/figure>\n\n\n\n<p>Android JetPack\u3092\u4f7f\u7528\u3057\u3066\u7c21\u5358\u306aMVVM\u8a2d\u8a08\u306b\u4fee\u6b63\u3057\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>UI\u3068\u30ed\u30b8\u30c3\u30af\u306e\u8cac\u4efb\u5206\u62c5\u304c\u3067\u304d\u3001\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306e\u4fdd\u5b88\u6027\u3082\u4e0a\u304c\u308a\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u3055\u3089\u306b\u306f\u3001\u3053\u308c\u307e\u3067\u958b\u767a\u8005\u304c\u6c17\u306b\u3057\u306a\u3051\u308c\u3070\u306a\u3089\u306a\u304b\u3063\u305f\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u7d61\u307f\u306eUI\u5b9f\u88c5\u304cJetPack\u30e9\u30a4\u30d6\u30e9\u30ea\u3067\u5438\u53ce\u3055\u308c\u3001\u52b9\u7387\u3088\u304f\u30a2\u30d7\u30ea\u958b\u767a\u304c\u53ef\u80fd\u306b\u306a\u3063\u305f\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u306e\u4ed6\u306b\u3082Navigation\u3001Room\u7b49\u306e\u958b\u767a\u30b9\u30d4\u30fc\u30c9\u3092\u4e0a\u3052\u308b\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u5f0a\u793e\u3067\u306f\u7a4d\u6975\u7684\u306b\u53d6\u308a\u5165\u308c\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-pullquote\" style=\"border-color:#0693e3\"><blockquote><p>\u53c2\u8003<\/p><\/blockquote><\/figure>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/developer.android.com\/topic\/libraries\/architecture\/livedata\" data-type=\"URL\" data-id=\"https:\/\/developer.android.com\/topic\/libraries\/architecture\/livedata\">LiveData &#8211; AndroidDevelopers<\/a><\/li><li><a href=\"https:\/\/developer.android.com\/topic\/libraries\/data-binding\" data-type=\"URL\" data-id=\"https:\/\/developer.android.com\/topic\/libraries\/data-binding\">DataBinding &#8211; AndroidDevelopers<\/a><\/li><\/ul>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-pullquote\" style=\"border-color:#0693e3\"><blockquote><p>\u6b21\u56de<\/p><\/blockquote><\/figure>\n\n\n\n<p>Bluetooth SPP\u901a\u4fe1\u306e\u5b9f\u88c5\u3092\u7d39\u4ecb\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:200px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n","protected":false},"author":10,"featured_media":157,"template":"","lc":[12],"lt":[16,15],"class_list":["post-175","article","type-article","status-publish","has-post-thumbnail","hentry","lc-introduction","lt-iot","lt-smartdevice"],"_links":{"self":[{"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/article\/175","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/article"}],"about":[{"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/types\/article"}],"author":[{"embeddable":true,"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/users\/10"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/media\/157"}],"wp:attachment":[{"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/media?parent=175"}],"wp:term":[{"taxonomy":"lc","embeddable":true,"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/lc?post=175"},{"taxonomy":"lt","embeddable":true,"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/lt?post=175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}