Android NFC标签读取耗时统计:计时器启停位置咨询
Hey there! Let's work through your NFC timing issue step by step. I see you've got the timer starting when a tag is detected, but you're stuck on where to stop it accurately. Let's fix that.
First, let's clarify the core problem: your current stop logic is tucked inside a try block in buildTagViews()—so if an encoding exception gets thrown, the timer never stops. Plus, we need to make sure the timer stops every time after we finish reading (or fail to read) the tag, and avoid duplicate timer runs.
Here's the revised plan and code changes:
1. First, create a dedicated stopTimer() method
This lets us reuse the stop logic everywhere, keeping things clean:
private void stopTimer() { if (handler != null) { handler.removeCallbacks(runnable); // Calculate the final elapsed time long totalElapsed = TimeBuff + (SystemClock.uptimeMillis() - StartTime); // Update the Timer TextView with the exact read time int minutes = (int) (totalElapsed / 60000); int seconds = (int) ((totalElapsed % 60000) / 1000); int millis = (int) (totalElapsed % 1000); Timer.setText(String.format("读取耗时: %d:%02d:%03d", minutes, seconds, millis)); // Reset timing variables for the next read TimeBuff = 0; MillisecondTime = 0; UpdateTime = 0; } }
2. Fix the buildTagViews() method
We'll call stopTimer() in a finally block to ensure it runs whether the read succeeds or fails:
private void buildTagViews(NdefMessage[] msgs) { if (msgs == null || msgs.length == 0) { stopTimer(); tvNFCContent.setText("NFC Content: 无数据"); return; } String text = ""; byte[] payload = msgs[0].getRecords()[0].getPayload(); String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; int languageCodeLength = payload[0] & 0063; try { text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); } catch (UnsupportedEncodingException e) { Log.e("UnsupportedEncoding", e.toString()); text = "读取失败: " + e.getMessage(); } finally { // Stop timer no matter if read succeeds or fails stopTimer(); } tvNFCContent.setText("NFC Content: " + text); }
3. Clean up the onNewIntent() method
Right now, you have duplicate NFC handling logic here. Let's streamline it and make sure we only start the timer once per tag detection, and stop it if we get an unknown action:
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); String action = intent.getAction(); if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { // Stop any existing timer before starting a new one handler.removeCallbacks(runnable); TimeBuff = 0; // Start the timer StartTime = SystemClock.uptimeMillis(); handler.postDelayed(runnable, 0); // Read the tag content readFromIntent(intent); // Show appropriate toasts if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { Toast.makeText(getApplicationContext(),"Ndefdiscovered",Toast.LENGTH_SHORT).show(); } else if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { mTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); Toast.makeText(getApplicationContext(),"Smartcard detected",Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(getApplicationContext(),"Undefined smartcard",Toast.LENGTH_SHORT).show(); // Stop timer for unknown actions stopTimer(); } }
A bonus optimization for your use case
Since your expected read time is only ~0.1ms, the repeating handler.postDelayed(runnable, 0) is overkill—it's updating the TextView way faster than needed, and might even skew your timing. Instead, you could skip the runnable entirely and just track start/end timestamps directly:
- Remove the
runnable,MillisecondTime,UpdateTime,Seconds,Minutes,MilliSecondsvariables - Replace the start logic with:
startTime = SystemClock.uptimeMillis(); - Replace the stop logic with:
long elapsedTime = SystemClock.uptimeMillis() - startTime; Timer.setText(String.format("读取耗时: %.3f毫秒", elapsedTime));
This is simpler and more accurate for ultra-fast operations like NFC reads.
Why this works
- The
stopTimer()method ensures we always clean up the handler callbacks and reset timing variables - Using
finallyguarantees the timer stops even if an error occurs during reading - We prevent duplicate timer runs by stopping any existing timer before starting a new one
Give these changes a try, and your timing should now accurately reflect how long it takes to detect and read the NFC tag!
内容的提问来源于stack exchange,提问作者Muhammad Haries

