I am currently developing an Android NFC application. This application contains a NavigationDrawer in which I can access 3 different fragments which each correspond to 3 different NFC features.
My goal is that when the onNewIntent method is called, so when the NFC tag is detected, I update the UI with the information in the tag.
At first, the update of the UI is done synchronously but the idea is to have something asynchronous by using coroutines in the future.
The problem is simply that the UI does not update when the onNewIntent function is called, can you help me?
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()))
}
MemoryFragment:
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
}
}
The 3 different fragments are created in the mobile_nagivation.xml file:
<?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>
The activity_main_drawer.xml file contains items that have the same IDs as the fragments:
<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>
If you want to update all fragments simultanousely use a Shared ViewModel
check the doc: https://developer.android.com/topic/libraries/architecture/viewmodel#sharing
In your case do:
private val memoryViewModel: MemoryViewModel by activityViewModels()