[Android] Jetpack Compose NFC with ViewModel

: ) YOUNG·2023년 5월 2일
1

안드로이드

목록 보기
9/30
post-thumbnail
post-custom-banner

NFC 찍었을 때 들어오는 데이터를 ViewModel의 MutableLiveData에 저장해서 해당 데이터를 observeAsState()를 통해서 recomposition을 동작하도록 한다.


NFC를 읽어오기 위해서 Manifest 기본 설정

Manifest.xml


    <uses-permission android:name="android.permission.NFC" />
    <uses-permission
        android:name="android.hardware.nfc"
        android:required="true" />

...

<activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:theme="@style/Theme.JetpackNFCTutorial">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/*" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
        </activity>

MainActivity에서 NFC 데이터 읽어오기



class MainActivity : ComponentActivity() {
    private lateinit var nfcAdapter: NfcAdapter
    private lateinit var pendingIntent: PendingIntent
    private lateinit var filters: Array<IntentFilter>
    private lateinit var navController: NavHostController
    private val nfcViewModel by viewModels<NfcViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetpackNFCTutorialTheme {
                MainScreen()
            }
        }

        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        if (nfcAdapter == null) {
            Toast.makeText(this, "NFC Tag", Toast.LENGTH_SHORT).show()
            finish()
        }

        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
        startActivity(intent)

        pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE)

        val filter = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) // 제일 마지막 호출(태그면 다 불림)
        filters = arrayOf(filter)
    } // End of onCreate

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)

        setIntent(intent)
        readNFC(getIntent())
    } // End of onNewIntent

    private fun readNFC(intent: Intent) {
        val message = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
        if (message != null) {
            message.forEach {
                val ndef = it as NdefMessage

                for (rec in ndef.records) {
//                    Log.d(TAG, "TNF  : ${rec.tnf}")
//                    Log.d(TAG, "ID   : ${String(rec.id)}")
//                    Log.d(TAG, "TYPE : ${String(rec.type)}")
//                    Log.d(TAG, "PLoad: ${String(rec.payload)}")

                    val strPload = String(rec.payload)
                    Log.d(TAG, "processNFC: ${strPload.substring(3)}")

                    // nfcViewModel setNfcData
                    nfcViewModel.setNfcData(newNfcData = strPload.substring(3))

                    val type = String(rec.type)
                    when (type) {
                        "T" -> {
                            val payload = rec.payload
                            Log.d(TAG, "processNFC type T : ${String(payload)}")
                        }
                        "U" -> {
                            val uri = rec.toUri()
                            startActivity(Intent().apply {
                                setAction(Intent.ACTION_SENDTO)
                                data = uri
                                Log.d(TAG, "processNFC: $uri")
                            })
                        }
                        "Sp" -> {
                            Log.d(TAG, "processNFC: ${String(rec.type)}")
                        }
                    }
                }
            }
        }
    } // End of processNFC
} // End of MainActivity class


nfcViewModel.kt


class NfcViewModel : ViewModel() {
    private val _nfcData = MutableLiveData<String>()
    val nfcData: LiveData<String>
        get() = _nfcData

    fun setNfcData(newNfcData: String) {
        _nfcData.value = newNfcData
        Log.d(TAG, "setNfcData: $newNfcData")
    } // End of setNfcData

} // End of NfcViewModel class

NFC 데이터를 표시해줄 Compose Screen

MainScreen.kt


@Composable
fun MainScreen(
    nfcViewModel: NfcViewModel = viewModel(LocalContext.current as ComponentActivity),
) {
    val nfcValue = nfcViewModel.nfcData.observeAsState()
    MainTextBody( nfcData = nfcValue.value.toString())

} // End of MainScreen


@Composable
fun MainTextBody(
    nfcData: String,
) {
    val context = LocalContext.current

    Column(
        Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = nfcData, fontSize = 24.sp)
    }
} // End of MainTextScreen

post-custom-banner

0개의 댓글