{"id":98,"date":"2021-07-19T15:55:18","date_gmt":"2021-07-19T06:55:18","guid":{"rendered":"https:\/\/www.avancesys.co.jp\/laboratory\/?post_type=article&#038;p=98"},"modified":"2021-07-19T16:25:44","modified_gmt":"2021-07-19T07:25:44","slug":"%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","status":"publish","type":"article","link":"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\/","title":{"rendered":"\u7b2c2\u56de \u9854\u8a8d\u8b58\u30c7\u30d0\u30a4\u30b9 Android\u7de8 \u301c JetPack\u3092\u4f7f\u3063\u3066ViewModel\u3092\u5b9f\u88c5\u3059\u308b \u301c"},"content":{"rendered":"\n<p>\u6700\u8fd1\u306eAndroid\u30a2\u30d7\u30ea\u306fJetPack\u30e9\u30a4\u30d6\u30e9\u30ea\u304c\u6d78\u900f\u3057\u3066\u304d\u305f\u3053\u3068\u3082\u3042\u308a\u3001MVVM\u3092\u4f7f\u3046\u3053\u3068\u306f\u5f53\u305f\u308a\u524d\u306e\u3088\u3046\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3088\u306d\u3002<\/p>\n\n\n\n<p>\u305d\u3053\u3067\u3001\u4eca\u56de\u306f\u3001\u30a2\u30d7\u30ea\u306eBluetooth\u63a5\u7d9a\u753b\u9762\u3092ViewModel + Coroutine + Lifecycle\u3092\u4f7f\u3063\u3066\u3001MVVM\u8a2d\u8a08\u306b\u3057\u3066\u307f\u3088\u3046\u3068\u601d\u3044\u307e\u3059\uff01<\/p>\n\n\n\n<p><a href=\"https:\/\/ja.wikipedia.org\/wiki\/Model_View_ViewModel\">MVVM\u3068\u306f? &#8211; Wikipedia\u53c2\u7167<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"473\" src=\"https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/06\/BluetoothView-1024x473.png\" alt=\"\" class=\"wp-image-101\" srcset=\"https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/06\/BluetoothView-1024x473.png 1024w, https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/06\/BluetoothView-300x138.png 300w, https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/06\/BluetoothView-768x354.png 768w, https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/06\/BluetoothView-1536x709.png 1536w, https:\/\/www.avancesys.co.jp\/laboratory\/wp-content\/uploads\/2021\/06\/BluetoothView-2048x945.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\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 is-style-default\" style=\"border-color:#0693e3\"><blockquote><p>\u65e2\u5b58\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9<\/p><\/blockquote><\/figure>\n\n\n\n<p>\u4e0b\u8a18\u306fBluetooth\u901a\u4fe1\u306e\u30a4\u30d9\u30f3\u30c8\u30cf\u30f3\u30c9\u30e9\u30fc\u3084\u30dc\u30bf\u30f3\u72b6\u614b\u5909\u5316\u3082\u542b\u3081\u305f\u65e2\u5b58\u30b3\u30fc\u30c9\u3067\u3059\u3002\u3053\u3053\u304b\u3089\u51e6\u7406\u3092\u5206\u96e2\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<div style=\"height:15px\" 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>class ConnectActivity : BaseActivity(), ISppClient {\n\n    private lateinit var deviceAdapter: ArrayAdapter&lt;String&gt;\n    private var btDeviceSet: Set&lt;BluetoothDevice&gt;? = null\n    private var btDevice: BluetoothDevice? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_connect)\n\n        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n\n        MyApplication.instance.sppClient.addListener(this)\n\n        deviceAdapter = ArrayAdapter(this,\n            R.layout.spinner_item\n        )\n        deviceAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item)\n        spinnerDevices.adapter = deviceAdapter\n\n        buttonConnect.setOnClickListener {\n            MyApplication.instance.sppClient.connect(btDevice)\n        }\n\n        buttonDisconnect.setOnClickListener {\n            MyApplication.instance.sppClient.disconnect()\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        \/\/ \u63a5\u7d9a\u4e2d\u306e\u5834\u5408\u306f\u305d\u306e\u30c7\u30d0\u30a4\u30b9\u3092\u521d\u671f\u9078\u629e\u9805\u76ee\u306b\u3059\u308b\n        if (MyApplication.instance.sppClient.isConnected()) {\n            btDevice = MyApplication.instance.sppClient.mBTDevice\n        }\n\n        deviceAdapter.clear()\n\n        val btAdapter = BluetoothAdapter.getDefaultAdapter()\n        btDeviceSet = btAdapter.bondedDevices\n        if (btDeviceSet != null) {\n\n            var selectIndex = 0\n            var index = 0\n\n            for (device in btDeviceSet!!) {\n                deviceAdapter.add(device.name)\n\n                if (device.name.equals(btDevice?.name)) {\n                    selectIndex = index\n                }\n                index++\n            }\n\n            if (btDevice == null && btDeviceSet!!.size &gt; 0) {\n                btDevice = btDeviceSet!!.first()\n                selectIndex = 0\n            }\n\n            if (btDevice != null && spinnerDevices.adapter.count &gt; selectIndex) {\n                spinnerDevices.setSelection(selectIndex, false)\n            }\n        }\n\n        spinnerDevices.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {\n            override fun onItemSelected(p0: AdapterView&lt;*&gt;?, p1: View?, p2: Int, p3: Long) {\n                \/\/ \u30c7\u30d0\u30a4\u30b9\u5909\u66f4\u6642\u306b\u5207\u65ad\u3059\u308b\n                MyApplication.instance.sppClient.disconnect()\n\n                if (btDeviceSet != null) {\n                    val selectedName = deviceAdapter.getItem(p2)\n                    for (device in btDeviceSet!!) {\n                        if (device.name.equals(selectedName)) {\n                            btDevice = device\n                            break\n                        }\n                    }\n                }\n            }\n\n            override fun onNothingSelected(p0: AdapterView&lt;*&gt;?) {\n            }\n        }\n\n        updateButtonState()\n    }\n\n    fun updateButtonState() {\n        if (MyApplication.instance.sppClient.isConnected()) {\n            buttonConnect.isEnabled = false\n            buttonDisconnect.isEnabled = true\n        } else {\n            buttonDisconnect.isEnabled = false\n            buttonConnect.isEnabled = (btDevice != null)\n        }\n    }\n\n    override fun onConnected(result: Boolean) {\n        runOnUiThread {\n            if (isRunning) {\n                if (result) {\n                    Toast.makeText(this, &quot;\u63a5\u7d9a\u6210\u529f&quot;, Toast.LENGTH_SHORT).show()\n                } else {\n                    Toast.makeText(this, &quot;\u63a5\u7d9a\u5931\u6557&quot;, Toast.LENGTH_SHORT).show()\n                }\n\n                updateButtonState()\n            }\n        }\n    }\n\n    override fun onDisconnected() {\n        runOnUiThread {\n            if (isRunning) {\n                Toast.makeText(this, &quot;\u63a5\u7d9a\u5207\u65ad&quot;, Toast.LENGTH_SHORT).show()\n                updateButtonState()\n            }\n        }\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>1. \u6e96\u5099<\/p><\/blockquote><\/figure>\n\n\n\n<p>Coroutine, Lifecycle \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 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-file=\"buid.gradle(app)\" 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; \/\/ \u8ffd\u52a0\n\nandroid {\n    ...\n\n    \/\/ \u8ffd\u52a0\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    \/\/ \u8ffd\u52a0\n    kotlinOptions {\n        jvmTarget = &#39;1.8&#39;\n    }\n\n    dependencies {\n        ...\n        \/\/ lifecycle \u8ffd\u52a0\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\n        \/\/ coroutine \u8ffd\u52a0\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. ViewModel\u306e\u5b9f\u88c5<\/p><\/blockquote><\/figure>\n\n\n\n<p>Bluetooth\u63a5\u7d9a\u753b\u9762\u3067\u306f\u30da\u30a2\u30ea\u30f3\u30b0\u3057\u305f\u30c7\u30d0\u30a4\u30b9\u306e\u30b9\u30d4\u30ca\u30fc\u8868\u793a\u3068\u63a5\u7d9a\u3001\u5207\u65ad\u30dc\u30bf\u30f3\u306e\u30a4\u30d9\u30f3\u30c8\u304c\u5b58\u5728\u3059\u308b\u305f\u3081\u3001\u3053\u308c\u3089\u306e\u51e6\u7406\u3092ViewModel\u3078\u8a18\u8ff0\u3057\u3066\u3044\u304d\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>ConnectViewModel.kt<\/strong><\/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-file=\"ConnectViewModel.kt\" data-lang=\"Swift\" data-show-lang=\"0\"><code>class ConnectViewModel(val app: Application) : AndroidViewModel(app) {\n\n    private var mBtDeviceSet: Set&lt;BluetoothDevice&gt;? = null      \/\/ \u30da\u30a2\u30ea\u30f3\u30b0\u6e08\u307f\u306e\u30c7\u30d0\u30a4\u30b9\u4e00\u89a7\n    private var mBtDevice: BluetoothDevice? = null              \/\/ \u63a5\u7d9a\u4e2d\u306e\u30c7\u30d0\u30a4\u30b9\n\n    val deviceAdapter: ArrayAdapter&lt;String&gt; = ArrayAdapter(app, R.layout.spinner_item)\n    val btDeviceSet get() = mBtDeviceSet\n    val btDevice get() = mBtDevice\n\n    init {\n        deviceAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item)\n    }\n\n    fun connectBtDevice() = MyApplication.instance.sppClient.connect(mBtDevice)\n\n    fun disconnectBtDevice() = MyApplication.instance.sppClient.disconnect()\n\n    val spinnerOnItemSelectedListener = object : SpinnerOnItemSelectedListener {\n        override var isSelectedFirst: Boolean = false\n\n        override fun onItemSelectedSpinner(\n            parent: AdapterView&lt;*&gt;?,\n            view: View?,\n            position: Int,\n            id: Long\n        ) {\n            \/\/ \u30c7\u30d0\u30a4\u30b9\u5909\u66f4\u6642\u306b\u5207\u65ad\u3059\u308b\n            MyApplication.instance.sppClient.disconnect()\n\n            if (mBtDeviceSet != null) {\n                val selectedName = deviceAdapter.getItem(position)\n                for (device in mBtDeviceSet!!) {\n                    if (device.name == selectedName) {\n                        mBtDevice = device\n                        break\n                    }\n                }\n            }\n        }\n\n        override fun onNothingSelected(parent: AdapterView&lt;*&gt;?) {\n        }\n    }\n\n    fun updateSpinner(callback: (selectIndex: Int) -&gt; Unit) =\n        viewModelScope.launch {\n            var selectIndex = 0\n\n            \/\/ \u63a5\u7d9a\u4e2d\u306e\u5834\u5408\u306f\u305d\u306e\u30c7\u30d0\u30a4\u30b9\u3092\u521d\u671f\u9078\u629e\u9805\u76ee\u306b\u3059\u308b\n            if (MyApplication.instance.sppClient.isConnected()) {\n                mBtDevice = MyApplication.instance.sppClient.mBTDevice\n            }\n\n            deviceAdapter.clear()\n\n            val btAdapter = BluetoothAdapter.getDefaultAdapter()\n            \/\/ \u30da\u30a2\u30ea\u30f3\u30b0\u6e08\u307f\u306e\u30c7\u30d0\u30a4\u30b9\u3092\u53d6\u5f97\n            mBtDeviceSet = btAdapter.bondedDevices\n\n            mBtDeviceSet?.let { btSet -&gt;\n                for ((index, device) in btSet.withIndex()) {\n                    deviceAdapter.add(device.name)\n\n                    if (device.name == mBtDevice?.name) {\n                        selectIndex = index\n                    }\n                }\n\n                if (btSet.isNotEmpty()) {\n                    mBtDevice = btSet.first()\n                    selectIndex = 0\n                }\n            }\n            callback(selectIndex)\n        }\n}<\/code><\/pre><\/div>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p>ViewModel\u3092\u4f5c\u6210\u3059\u308b\u969b\u306f\u3001<mark id=\"keyword\">ViewModel<\/mark>\u3082\u3057\u304f\u306f<mark id=\"keyword\">AndroidViewModel<\/mark>\u3092\u7d99\u627f\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u4eca\u56de\u306f<mark id=\"keyword\">Context<\/mark>\u3092ViewModel\u3067\u4f7f\u7528\u3059\u308b\u305f\u3081\u3001AndroidViewModel\u3092\u7d99\u627f\u3057\u3066\u3044\u307e\u3059\u3002Context\u3092\u4f7f\u7528\u3057\u306a\u3044\u5834\u5408\u306fViewModel\u3067\u826f\u3044\u3067\u3059\u3002<\/p>\n\n\n\n<p>Activity\u3067\u3053\u308c\u307e\u3067\u7ba1\u7406\u3057\u3066\u3044\u305f\u4ee5\u4e0b\u306e\u8981\u7d20\u306f\u5168\u3066ViewModel\u3078\u79fb\u884c\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>\u30b9\u30d4\u30ca\u30fc\u30a2\u30a4\u30c6\u30e0\uff08deviceAdapter\uff09<\/li><li>Bluetooth\u30c7\u30d0\u30a4\u30b9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08btDeviceSet, btDevice\uff09<\/li><li>\u63a5\u7d9a\u30dc\u30bf\u30f3\u306e\u5185\u90e8\u51e6\u7406\uff08connectBtDevice()\uff09<\/li><li>\u5207\u65ad\u30dc\u30bf\u30f3\u306e\u5185\u90e8\u51e6\u7406\uff08disconnectBtDevice()\uff09<\/li><li>\u30b9\u30d4\u30ca\u30fc\u30a2\u30a4\u30c6\u30e0\u3092\u30bf\u30c3\u30d7\u3057\u305f\u3068\u304d\u306e\u5185\u90e8\u51e6\u7406\uff08spinnerOnItemSelectedListener\uff09<\/li><\/ul>\n\n\n\n<p>\u3053\u308c\u306fView\u306b\u95a2\u3059\u308b\u51e6\u7406\u306fActivity\u3001View\u306e\u72b6\u614b\u7ba1\u7406\u3092ViewModel\u3001\u3068\u5f79\u5272\u3092\u5206\u3051\u3066\u3044\u308b\u305f\u3081\u3067\u3059\u3002<\/p>\n\n\n\n<p><mark id=\"keyword\">updateSpinner()<\/mark>\u306f\u7aef\u672b\u8a2d\u5b9a\u304b\u3089\u30da\u30a2\u30ea\u30f3\u30b0\u30c7\u30d0\u30a4\u30b9\u3092\u8ffd\u52a0\u3057\u305f\u3042\u3068\u3001\u30a2\u30d7\u30ea\u3078\u9077\u79fb\u3057\u305f\u3053\u3068\u3092\u60f3\u5b9a\u3057\u3066<mark id=\"keyword\">onResume()<\/mark>\u304b\u3089\u547c\u3073\u51fa\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u3053\u3067\u4e0b\u8a18<mark id=\"keyword\">viewModelScope<\/mark>\u304c\u767b\u5834\u3057\u307e\u3059\u304c\u3001\u3053\u308c\u306fViewModel\u7528\u306b\u8a2d\u8a08\u3055\u308c\u305f\u30b3\u30eb\u30fc\u30c1\u30f3\u3067\u3059\u3002ViewModel\u304c\u7834\u68c4\u3055\u308c\u308b\u3068\u304d\u3001\u3053\u306e\u30b3\u30eb\u30fc\u30c1\u30f3\u5185\u3067\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u51e6\u7406\u306f\u5168\u3066\u81ea\u52d5\u7684\u306b\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u308b\u4e8b\u306b\u306a\u3063\u3066\u3044\u308b\u305f\u3081\u3001<mark id=\"keyword\">AsyncTask<\/mark>\u7b49\u3067\u7ba1\u7406\u3059\u308b\u5fc5\u8981\u304c\u7121\u304f\u306a\u308b\u3068\u3044\u3046\u3053\u3068\u306b\u306a\u308a\u307e\u3059\u306d\u3002<\/p>\n\n\n\n<p>\u975e\u540c\u671f\u51e6\u7406\u304b\u3089UI\u66f4\u65b0\u3092\u3059\u308b\u3088\u3046\u306a\u3068\u304d\u306f\u7a4d\u6975\u7684\u306b\u4f7f\u3063\u3066\u3044\u304d\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>viewModelScope.launch {\n    ...\n}<\/code><\/pre><\/div>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u5c11\u3057\u8a71\u304c\u305d\u308c\u3066\u3057\u307e\u3046\u306e\u3067\u3059\u304c\u3001\u30b9\u30d4\u30ca\u30fc\u3078<mark id=\"keyword\">AdapterView.OnItemSelectedListener<\/mark>\u3092\u30a2\u30bf\u30c3\u30c1\u3057\u305f\u969b\u306b<mark id=\"keyword\">onItemSelected()<\/mark>\u304c\u547c\u3070\u308c\u3066\u3057\u307e\u3046\u306e\u3067\u3001\u3053\u308c\u3092\u56de\u907f\u3059\u308b\u305f\u3081\u306e\u5b9f\u88c5\u3092<mark id=\"keyword\">SpinnerOnItemSelectedListener<\/mark>\u306b\u3057\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>3. Activity\u306e\u5b9f\u88c5<\/p><\/blockquote><\/figure>\n\n\n\n<p>Activity\u306e\u5b9f\u88c5\u306f\u7c21\u5358\u3067\u3059\uff01<\/p>\n\n\n\n<p>ViewModel\u3092\u751f\u6210\u3057\u3001\u30b9\u30d4\u30ca\u30fc\u3084\u30dc\u30bf\u30f3\u3068\u95a2\u9023\u4ed8\u3051\u308b\u3060\u3051\u3067\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>class ConnectActivity : BaseActivity(), ISppClient {\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        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n\n        \/\/ SPP\u901a\u4fe1\u306e\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n        MyApplication.instance.sppClient.addListener(this)\n\n        \/\/ \u30b9\u30d4\u30ca\u30fc\n        spinnerDevices.adapter = viewModel.deviceAdapter\n        spinnerDevices.onItemSelectedListener = viewModel.spinnerOnItemSelectedListener\n\n        \/\/ \u63a5\u7d9a\u30dc\u30bf\u30f3\n        buttonConnect.setOnClickListener {\n            viewModel.connectBtDevice()\n        }\n\n        \/\/ \u5207\u65ad\u30dc\u30bf\u30f3\n        buttonDisconnect.setOnClickListener {\n            viewModel.disconnectBtDevice()\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        updateButtonState()\n    }\n\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>\u53c2\u8003<\/p><\/blockquote><\/figure>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/developer.android.com\/topic\/libraries\/architecture\/viewmodel?hl=ja\">https:\/\/developer.android.com\/topic\/libraries\/architecture\/viewmodel?hl=ja<\/a><\/li><li><a href=\"https:\/\/developer.android.com\/kotlin\/coroutines\">https:\/\/developer.android.com\/kotlin\/coroutines<\/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>\u307e\u3060\u5c11\u3057\u4e0d\u5341\u5206\u306a\u306e\u3067\u3001\u30dc\u30bf\u30f3\u306e\u8868\u793a\u72b6\u614b\u3092 ViewModel + LiveData + DataBinding \u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u3067\u3088\u308a\u3001MVVM\u8a2d\u8a08\u306b\u8fd1\u3065\u3051\u308b\u5b9f\u88c5\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-98","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\/98","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=98"}],"wp:term":[{"taxonomy":"lc","embeddable":true,"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/lc?post=98"},{"taxonomy":"lt","embeddable":true,"href":"https:\/\/www.avancesys.co.jp\/laboratory\/wp-json\/wp\/v2\/lt?post=98"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}