正在更新来自 Activity 的 UI 片段

Updating UI fragment from Activity

我目前正在开发 Android NFC 应用程序。此应用程序包含一个 NavigationDrawer,我可以在其中访问 3 个不同的片段,每个片段对应 3 个不同的 NFC 功能。

我的目标是当 onNewIntent 方法被调用时,当检测到 NFC 标签时,我用标签中的信息更新 UI。

起初,UI 的更新是同步完成的,但我们的想法是将来通过使用协程来实现异步。

问题很简单,当调用onNewIntent函数时UI没有更新,你能帮我吗?

MainActivity:

private val memoryViewModel: MemoryViewModel by viewModels()

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

    checkNFC()
    mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
    setNfcIntent()

    configureToolbar()

    val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
    val navView: NavigationView = findViewById(R.id.nav_view)
    val navController = findNavController(R.id.nav_host_fragment)
    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    appBarConfiguration = AppBarConfiguration(setOf(
            R.id.nav_memory, R.id.nav_tag, R.id.nav_product), drawerLayout)
    setupActionBarWithNavController(navController, appBarConfiguration)
    navView.setupWithNavController(navController)
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    // Inflate the menu; this adds items to the action bar if it is present.
    menuInflater.inflate(R.menu.main, menu)
    return true
}

override fun onSupportNavigateUp(): Boolean {
    val navController = findNavController(R.id.nav_host_fragment)
    return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}

private fun configureToolbar() {
    val toolbar: Toolbar = findViewById(R.id.toolbar)
    setSupportActionBar(toolbar)
}

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
    Log.d(TAG, "Card ID: " + Tools.byteArrayToHex(tag!!.id))
    val techList = tag!!.techList

    updateUI()

    //Check that the discovered tag is a vicinity tag
    if (techList[0] == "android.nfc.tech.NfcV") {
        val tagUid = tag!!.id
        nfcvTag = NfcV.get(tag)

        //ISO/IEC 15693 tags can be operated in two modes:
        // Select mode and Addressed mode.
        //To work in the select mode it is needed to send a SELECT
        // command at the beginning of communic.
        //In the address mode, the tag UID is sent within each command.
        //This application works in SELECT MODE.
        val select_command: ByteArray = RFCommands.cmd_select
        System.arraycopy(tagUid, 0, select_command, 2, 8)
        if (nfcvTag != null) {
            try {
                nfcvTag!!.connect()
                val select_respo: ByteArray = nfcvTag!!.transceive(select_command)
                Log.d(TAG, "Select response: " +
                        Tools.byteArrayToHex(select_respo))
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }
}

private fun updateUI() {
    memoryViewModel.setManufacturer(nfcManufacturer.getValue(tag!!.id[6].toInt()))
}

内存片段:

class MemoryFragment : Fragment() {

    private lateinit var memoryViewModel: MemoryViewModel

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        memoryViewModel =
                ViewModelProvider(this).get(MemoryViewModel::class.java)
        val root = inflater.inflate(R.layout.fragment_memory, container, false)

        val icManuf: TextView = root.findViewById(R.id.ic_manufacturer_value)
        memoryViewModel.icManufacturer.observe(viewLifecycleOwner, Observer {
            icManuf.text = it
        })
        return root
    }
}

MemoryViewModel:

class MemoryViewModel : ViewModel() {
    // The current IC Manufacturer
    private val _icManufacturer = MutableLiveData<String>()

    val icManufacturer: LiveData<String>
        get() = _icManufacturer

    init {
        _icManufacturer.value = ""
    }

    fun setManufacturer(value: String) {
        _icManufacturer.value = value
    }
}

mobile_nagivation.xml 文件中创建了 3 个不同的片段:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    app:startDestination="@+id/nav_memory">

    <fragment
        android:id="@+id/nav_memory"
        android:name="com.bodet.bodettag.ui.memory.MemoryFragment"
        android:label="@string/menu_memory"
        tools:layout="@layout/fragment_memory" />

    <fragment
        android:id="@+id/nav_tag"
        android:name="com.bodet.bodettag.ui.tag.TagFragment"
        android:label="@string/menu_tag_settings"
        tools:layout="@layout/fragment_tag" />

    <fragment
        android:id="@+id/nav_product"
        android:name="com.bodet.bodettag.ui.product.ProductFragment"
        android:label="@string/menu_product_settings"
        tools:layout="@layout/fragment_product" />
</navigation>

activity_main_drawer.xml 文件包含与片段具有相同 ID 的项目:

<item android:title="@string/menu_nfc">
    <menu>
        <group
            android:id="@+id/menu_top"
            android:checkableBehavior="single">
            <item
                android:id="@+id/nav_memory"
                android:icon="@drawable/ic_baseline_contactless_24"
                android:title="@string/menu_memory" />
            <item
                android:id="@+id/nav_tag"
                android:icon="@drawable/ic_baseline_memory_24"
                android:title="@string/menu_tag_settings" />
            <item
                android:id="@+id/nav_product"
                android:icon="@drawable/ic_icon_visio_x7_hov"
                android:title="@string/menu_product_settings" />
        </group>
    </menu>
</item>

您的问题是 ViewModelProviders returns 个不同的 viewModel 实例,当您尝试分配一些 _icManufacturer 值时,它会在 activity的 ViewModel,但不在片段的 ViewModel 中。

您应该添加以下代码

片段:

fun setManufacturerValue(icManufacturer: String) {
    // val icManuf: TextView = root.findViewById(R.id.ic_manufacturer_value)
    // icManuf.text = icManufacturer
    // or
    // memoryViewModel.setManufacturer(icManufacturer)
}

Activity:

private fun updateUI() {
    val navController = findNavController(R.id.nav_host_fragment)
    val fragment = navController.currentDestination as? MemoryFragment
    fragment?.setManufacturer(nfcManufacturer.getValue(tag!!.id[6].toInt()))
}

如果您想同时更新所有片段,请使用共享视图模型

查看文档:https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

在你的情况下:

private val memoryViewModel: MemoryViewModel by activityViewModels()