【问题标题】:NFC Android reading NDEF tag multiple timesNFC Android 多次读取 NDEF 标签
【发布时间】:2016-04-25 17:52:09
【问题描述】:

我有一个可以读取 NDEF 标签的应用,没什么大不了的 :-)

我想多次读取一个 NDEF 标签,显然是要相应地更新标签。想象一下,我的 NDEF 标记将包含时间 (hh:mm:ss),当我用我的应用程序读取它时,我想在手机上看到时间的变化。 如果我将手机放在标签上打开和关闭的位置,这有点工作,但我希望能够自动检测 NDEF 标签,只要它在那里,我想每 x 秒读取一次它的内容。

我找到了这个链接: Write NDEF message multiple times to same tag? 但它是关于写几次,我想读。

我找到了这个链接: How to find out whether an NFC tag is still in range of an Android now? 什么是开始,但我不知道如何更新标签。

我很挣扎,我什至不知道我尝试做的事情在技术上是否可行。

有没有人有一些关于如何做到这一点的提示? 干杯

更多信息

这是我的 onCreate

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /// trying something
        ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
        exec.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                // do stuff
                Log.d(TAG, "i am printing ");
            }
        }, 0, 5, TimeUnit.SECONDS);

        new Thread(new Runnable() {
            @Override
            public void run() {
                // here ask for TAG
                // read the TAG
                // and update the clock
            }
        }).start(); // Start the operation

        /////////////////

        mTextView = (TextView) findViewById(R.id.textView_explanation);

        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);

        if (mNfcAdapter == null) {

            // Stop here, we definitely need NFC
            Toast.makeText(this, "This device doesn't support NFC.",
                    Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        if (!mNfcAdapter.isEnabled()) {
            mTextView.setText("NFC is currently disabled on this device.");
        }

        handleIntent(getIntent());
    }

还有我的handleIntent:

private void handleIntent(Intent intent) {
        String action = intent.getAction();
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {

            String type = intent.getType();
            if (MIME_TEXT_PLAIN.equals(type)) {

                Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                new NdefReaderTask().execute(tag);

            } else {
                Log.d(TAG, "Wrong mime type: " + type);
            }
        } else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {

            // In case we would still use the Tech Discovered Intent
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            String[] techList = tag.getTechList();
            String searchedTech = Ndef.class.getName();

            for (String tech : techList) {
                if (searchedTech.equals(tech)) {
                    new NdefReaderTask().execute(tag);
                    break;
                }
            }
        }
    }

在 ScheduledExecutorService 中,我添加了“Log.d(TAG,”我正在打印“);”,只是为了尝试理解它确实可以正常工作并定期打印。我没有得到的是,如果我要求 TAG,读取 TAG 并更新新线程中的时钟,我应该在 ScheduledExecutorService 中做什么,以及如何要求 TAG,读取 TAG 并更新新线程内的时钟,当它当前在 onCreate 方法之外完成时?例如,读取的结果发布在我的 onPostExecute 方法中的 textView 中。

抱歉,我已经尝试观看一些教程和示例,但我仍然不明白。

更多信息 2

这是我的全部代码。读取标签需要更长的时间,有时不需要。我不知道如何以及在哪里更新标签,以防出现问题。完全迷路了:-(

package uk.co.xxx.xxx;

import android.nfc.FormatException;
import android.support.v7.app.AppCompatActivity;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

    public static final String MIME_TEXT_PLAIN = "text/plain";
    public static final String TAG = "NfcDemo";

    private TextView mTextView;
    private NfcAdapter mNfcAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /// trying something
        ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
        exec.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                // do stuff
                handleIntent(getIntent());
                Log.d(TAG, "i am printing ");
            }
        }, 0, 5, TimeUnit.SECONDS);
        /////////////////

        mTextView = (TextView) findViewById(R.id.textView_explanation);

        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);

        if (mNfcAdapter == null) {

            Toast.makeText(this, "This device doesn't support NFC.",
                    Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        if (!mNfcAdapter.isEnabled()) {
            mTextView.setText("NFC is currently disabled on this device.");
        }

        handleIntent(getIntent());
    }



    @Override
    protected void onResume() {
        super.onResume();

        /**
         * It's important, that the activity is in the foreground (resumed). Otherwise
         * an IllegalStateException is thrown.
         */
        setupForegroundDispatch(this, mNfcAdapter);
    }

    @Override
    protected void onPause() {
        /**
         * Call this before onPause, otherwise an IllegalArgumentException is thrown as well.
         */
        stopForegroundDispatch(this, mNfcAdapter);

        super.onPause();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        /**
         * This method gets called, when a new Intent gets associated with the current activity instance.
         * Instead of creating a new activity, onNewIntent will be called. For more information have a look
         * at the documentation.
         *
         * In our case this method gets called, when the user attaches a Tag to the device.
         */
        handleIntent(intent);
    }


    private void handleIntent(Intent intent) {
        String action = intent.getAction();
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {

            String type = intent.getType();
            if (MIME_TEXT_PLAIN.equals(type)) {

                Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                new NdefReaderTask().execute(tag);


            } else {
                Log.d(TAG, "Wrong mime type: " + type);
            }
        } else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {

            // In case we would still use the Tech Discovered Intent
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            String[] techList = tag.getTechList();
            String searchedTech = Ndef.class.getName();

            for (String tech : techList) {
                if (searchedTech.equals(tech)) {
                    new NdefReaderTask().execute(tag);
                    break;
                }
            }
        }
    }


    public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
        final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

        final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);

        IntentFilter[] filters = new IntentFilter[1];
        String[][] techList = new String[][]{};


        filters[0] = new IntentFilter();
        filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
        filters[0].addCategory(Intent.CATEGORY_DEFAULT);
        try {
            filters[0].addDataType(MIME_TEXT_PLAIN);
        } catch (MalformedMimeTypeException e) {
            throw new RuntimeException("Check your mime type.");
        }

        adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
    }


    public static void stopForegroundDispatch(final Activity activity, NfcAdapter adapter) {
        adapter.disableForegroundDispatch(activity);
    }

    /**
     * Background task for reading the data. Do not block the UI thread while reading.
     */

    private class NdefReaderTask extends AsyncTask<Tag, Void, String> {

        @Override
        protected String doInBackground(Tag... params) {
            Tag tag = params[0];

            Ndef ndef = Ndef.get(tag);
            if (ndef == null) {
                // NDEF is not supported by this Tag.
                return null;
            }

            NdefMessage ndefMessage = ndef.getCachedNdefMessage();

            NdefRecord[] records = ndefMessage.getRecords();
            for (NdefRecord ndefRecord : records) {
                if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
                    try {
                        return readText(ndefRecord);
                    } catch (UnsupportedEncodingException e) {
                        Log.e(TAG, "Unsupported Encoding", e);
                    }
                }
            }

            return null;
        }

        private String readText(NdefRecord record) throws UnsupportedEncodingException {

            byte[] payload = record.getPayload();

            // Get the Text Encoding

            String textEncoding = new String ("");
            if ((payload[0] & 128) == 0) {
                textEncoding = "UTF-8";
            } else {
                textEncoding = "UTF-16";
            }

            // Get the Language Code
            int languageCodeLength = payload[0] & 63;


            // Get the Text
            return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
        }

        @Override
        protected void onPostExecute(String result) {
            if (result != null) {
                mTextView.setText("The time is: \n" + result);
            }
        }
    }
}

【问题讨论】:

  • NfcAdapter查看EXTRA_READER_PRESENCE_CHECK_DELAY
  • @Pim 我不确定我是否理解。我读过它,但它不是做与我想做的相反的事情,比如延迟识别标签,而我想要的是继续看到它?可能是我误解了我读到的内容。请您再解释一下好吗?

标签: android nfc ndef


【解决方案1】:

使用TAG = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);,您可以获得标签。现在,您可以每 x 秒检查一次 TAG,如果它不为空(或者它具有最后检测到的类型),您可以读取标签并更新时钟(我想它是一个文本视图)。 您可以在 Thread 中执行此操作,例如:

new Thread(new Runnable() {
  @Override
  public void run() {
  // here ask for TAG
  // read the TAG
  // and update the clock             
  }
}).start(); // Start the operation

我希望我正确理解了您的问题。

【讨论】:

  • 感谢您的回答。我想我明白你的意思以及如何去做,但在我尝试之前,(我对 Android 不是很好):我是否将这个新线程放在我的 MainActivity 中的任何位置?我以前从未创建过新线程。
  • 要完善我的答案,您可以使用此方法:link。您只需从 MainActivity 的 onCreate 方法中的任何位置复制第一个答案中的代码。将每 x 秒启动一次此线程。
  • 我已经用更多信息编辑了我最初的问题,以显示一些我仍然没有得到的东西
  • 在哪里打印(在第一个线程的 run 方法内),您要求带有 mNfcAdapter = NfcAdapter.getDefaultAdapter(this);TAG = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 的标签。第二个线程你可以删除它。
  • 所以,它将类似于:/// trying something ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); exec.scheduleAtFixedRate(new Runnable() { @Override public void run() { intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // ask for tag, read it and update the clock Log.d(TAG, "i am printing "); } }, 0, 5, TimeUnit.SECONDS);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多