当前位置: 首页 > 知识库问答 >
问题:

NFC接待后,保持当前活动

邢硕
2023-03-14

我有一个应用程序,似乎工作得很好,可以通过NFC完美地传输数据。我有一个主要活动,一个传输数据的活动,还有一个接收数据的不同活动。

发送方的活动效果很好,但当接收方获得NFC意图时,它会重新启动应用程序,使其返回到主活动。

我不确定这是为什么。我希望它拒绝任何推送,除非用户已经在那个活动中,如果他们在,留在那个活动中并处理NFC意图。

以下是清单:

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".Timer" />
<activity android:name=".AddSlaves"
          android:label="Add Slave Devices"
          android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>
<activity android:name=".JoinSrv"
          android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

下面是sender类:

public class JoinSrv extends Activity implements NfcAdapter.OnNdefPushCompleteCallback, NfcAdapter.CreateNdefMessageCallback {
    //The array lists to hold our messages
    private ArrayList<String> messagesToSendArray = new ArrayList<>();
    private ArrayList<String> messagesReceivedArray = new ArrayList<>();

    //Text boxes to add and display our messages
    private NfcAdapter mNfcAdapter;

    //Save our Array Lists of Messages for if the user navigates away
    @Override
    public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putStringArrayList("messagesToSend", messagesToSendArray);
        savedInstanceState.putStringArrayList("lastMessagesReceived", messagesReceivedArray);
    }

    //Load our Array Lists of Messages for when the user navigates back
    @Override
    public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        messagesToSendArray = savedInstanceState.getStringArrayList("messagesToSend");
        messagesReceivedArray = savedInstanceState.getStringArrayList("lastMessagesReceived");
    }

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


        //Check if NFC is available on device
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter != null) {
            //Handle some NFC initialization here
        } else {
            Toast.makeText(this, "NFC not available on this device",
                    Toast.LENGTH_SHORT).show();
        }

        //Check if NFC is available on device
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter != null) {
            //This will refer back to createNdefMessage for what it will send
            mNfcAdapter.setNdefPushMessageCallback(this, this);

            //This will be called if the message is sent successfully
            mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
        }
    }

    @Override
    public NdefMessage createNdefMessage(NfcEvent event) {
        //This will be called when another NFC capable device is detected.
        //We'll write the createRecords() method in just a moment
        NdefRecord[] recordsToAttach = createRecords();
        //When creating an NdefMessage we need to provide an NdefRecord[]
        return new NdefMessage(recordsToAttach);
    }

    @Override
    public void onNdefPushComplete(NfcEvent event) {
        //This is called when the system detects that our NdefMessage was
        //Successfully sent.
        messagesToSendArray.clear();
    }

    public NdefRecord[] createRecords() {
        NdefRecord[] records = new NdefRecord[1];
        //To Create Messages Manually if API is less than
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {

            byte[] payload = "192.168.1.100".
                    getBytes(Charset.forName("UTF-8"));
            NdefRecord record = new NdefRecord(
                    NdefRecord.TNF_WELL_KNOWN,      //Our 3-bit Type name format
                    NdefRecord.RTD_TEXT,            //Description of our payload
                    new byte[0],                    //The optional id for our Record
                    payload);                       //Our payload for the Record

            records[1] = record;

        }
        //Api is high enough that we can use createMime, which is preferred.
        else {

                byte[] payload = "192.168.1.100".
                        getBytes(Charset.forName("UTF-8"));

                NdefRecord record = NdefRecord.createMime("text/plain",payload);
                records[1] = record;

        }
        records[messagesToSendArray.size()] =
                NdefRecord.createApplicationRecord(getPackageName());
        return records;
    }

    private void handleNfcIntent(Intent NfcIntent) {
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(NfcIntent.getAction())) {
            Parcelable[] receivedArray =
                    NfcIntent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

            if (receivedArray != null) {
                messagesReceivedArray.clear();
                NdefMessage receivedMessage = (NdefMessage) receivedArray[0];
                NdefRecord[] attachedRecords = receivedMessage.getRecords();

                for (NdefRecord record : attachedRecords) {
                    String string = new String(record.getPayload());
                    //Make sure we don't pass along our AAR (Android Application Record)
                    if (string.equals(getPackageName())) {
                        continue;
                    }
                    messagesReceivedArray.add(string);
                }
                Toast.makeText(this, "Received " + messagesReceivedArray.size() +
                        " Messages", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(this, "Received Blank Parcel", Toast.LENGTH_LONG).show();
            }
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        handleNfcIntent(intent);
    }

    @Override
    public void onResume() {
        super.onResume();
        handleNfcIntent(getIntent());
    }
}

以下是receiver类:

public class AddSlaves extends Activity implements NfcAdapter.OnNdefPushCompleteCallback, NfcAdapter.CreateNdefMessageCallback{
    //The array lists to hold our messages
    private ArrayList<String> messagesToSendArray = new ArrayList<>();
    private ArrayList<String> messagesReceivedArray = new ArrayList<>();

    //Text boxes to add and display our messages
    private EditText txtBoxAddMessage;
    private TextView txtReceivedMessages;
    private TextView txtMessagesToSend;
    private NfcAdapter mNfcAdapter;

    private  void updateTextViews() {
        txtReceivedMessages.setText("Messages Received:\n");
        //Populate our list of messages we have received
        if (messagesReceivedArray.size() > 0) {
            for (int i = 0; i < messagesReceivedArray.size(); i++) {
                txtReceivedMessages.append(messagesReceivedArray.get(i));
                txtReceivedMessages.append("\n");
            }
        }
    }

    //Save our Array Lists of Messages for if the user navigates away
    @Override
    public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putStringArrayList("lastMessagesReceived",messagesReceivedArray);
    }

    //Load our Array Lists of Messages for when the user navigates back
    @Override
    public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        messagesReceivedArray = savedInstanceState.getStringArrayList("lastMessagesReceived");
    }

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

        txtReceivedMessages = (TextView) findViewById(R.id.txtMessagesReceived);
        Button btnAddMessage = (Button) findViewById(R.id.buttonAddMessage);


        //Check if NFC is available on device
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if(mNfcAdapter != null) {
            //Handle some NFC initialization here
        }
        else {
            Toast.makeText(this, "NFC not available on this device",
                    Toast.LENGTH_SHORT).show();
        }

        //Check if NFC is available on device
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if(mNfcAdapter != null) {
            //This will refer back to createNdefMessage for what it will send
            mNfcAdapter.setNdefPushMessageCallback(this, this);

            //This will be called if the message is sent successfully
            mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
        }
    }

    @Override
    public NdefMessage createNdefMessage(NfcEvent event) {
        //This will be called when another NFC capable device is detected.
        return null;

    }

    @Override
    public void onNdefPushComplete(NfcEvent event) {
        //This is called when the system detects that our NdefMessage was
        //Successfully sent.
        messagesToSendArray.clear();
    }


    private void handleNfcIntent(Intent NfcIntent) {
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(NfcIntent.getAction())) {
            Parcelable[] receivedArray =
                    NfcIntent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

            if(receivedArray != null) {
                messagesReceivedArray.clear();
                NdefMessage receivedMessage = (NdefMessage) receivedArray[0];
                NdefRecord[] attachedRecords = receivedMessage.getRecords();

                for (NdefRecord record:attachedRecords) {
                    String string = new String(record.getPayload());
                    //Make sure we don't pass along our AAR (Android Application Record)
                    if (string.equals(getPackageName())) { continue; }
                    messagesReceivedArray.add(string);
                }
                Toast.makeText(this, "Received " + messagesReceivedArray.size() +
                        " Messages", Toast.LENGTH_LONG).show();
                updateTextViews();
            }
            else {
                Toast.makeText(this, "Received Blank Parcel", Toast.LENGTH_LONG).show();
            }
        }
    }


    @Override
    public void onNewIntent(Intent intent) {
        handleNfcIntent(intent);
    }

    @Override
    public void onResume() {
        super.onResume();
        updateTextViews();
        handleNfcIntent(getIntent());
    }
}

共有1个答案

柯振濂
2023-03-14

您的发件人活动html" target="_blank">代码中有几个问题:

>

  • 你存储了MessagesToSendArray,但是你从来没有用数据填充这个数组列表(即MessagesToSendArray.size()总是0)。由于每当调用createNDefMessage()时,您都会新鲜创建NDEF消息,因此无需保存和恢复MessagesToSendArray

    您写道希望在一个活动中发送NDEF消息,但希望在另一个活动中接收NFC事件。但是,您注册了发件人活动以接收清单中的NDEF_发现事件。如果您不想接收和处理这些事件,则无需在清单中使用NDEF_发现的意图过滤器。

    此外,无需在发送方活动中处理NDEF_发现的意图(即,您可以安全地删除方法onNewIntent()handleNfcIntent())。

    在果冻豆下面的Android版本上,您创建了一个结构无效的NFC论坛文本记录。文本RTD请求一个以表单编码的有效负载(也请参阅这篇文章)

    +----------+---------------+--------------------------------------+
    | Status   | Language Code | Text                                 |
    | (1 byte) | (n bytes)     | (m bytes)                            |
    +----------+---------------+--------------------------------------+
    
    public static NdefRecord createTextRecord(String language, String text) {
        byte[] languageBytes;
        byte[] textBytes;
        try {
            languageBytes = language.getBytes("US-ASCII");
            textBytes = text.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new AssertionError(e);
        }
    
        byte[] recordPayload = new byte[1 + (languageBytes.length & 0x03F) + textBytes.length];
    
        recordPayload[0] = (byte)(languageBytes.length & 0x03F);
        System.arraycopy(languageBytes, 0, recordPayload, 1, languageBytes.length & 0x03F);
        System.arraycopy(textBytes, 0, recordPayload, 1 + (languageBytes.length & 0x03F), textBytes.length);
    
        return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, null, recordPayload);
    }
    

    我不清楚为什么你在果冻豆以下的Android版本上创建一个NFC论坛文本记录,而在果冻豆及以上版本上创建一个MIME类型记录。您应该保持一致,并在所有平台上创建相同的记录类型(请参见方法NDefRecord.create文本记录(“en”,“字符串”),不低于API级别21):

    String text = "192.168.1.100";
    String language = "en";
    
    NdefRecord record;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        record = NdefRecord.createTextRecord(language, text);
    } else {
        record = createTextRecord(language, text);
    }
    

    最后,在createRecords()中创建数组recordsas

    NdefRecord[] records = new NdefRecord[1];
    

    因此,数组中有一个元素可以在索引0处访问。Hoever,稍后尝试访问元素1:

    records[1] = record;
    

    这将导致一个IndexOutOfBound异常。由于Android通过createNDefMessage()回调调用了createNotes(),因此回调失败(由于运行时异常),Android将不会使用您的NDEF消息。相反,Android将为您的应用使用默认的NDEF消息。此默认NDEF消息包含一个Android应用程序记录,该记录将导致您的主活动被调用(因为您的其他活动都没有注册为默认NDEF消息的特定内容而被启动);请参见NFC标签检测不是调用NewIntent,而是从主活动启动。因此,您需要将记录中存储新创建的NDEF记录的偏移量更改为0:

    records[0] = record;
    

    此外,您需要删除该行

    records[messagesToSendArray.size()] =
        NdefRecord.createApplicationRecord(getPackageName());
    

    因为这将用Android应用程序记录覆盖以前存储在索引0处的NDEF记录(MessagesToSendArray.size()为0)。同样,这将导致您的主要活动被启动,因为您没有在清单中注册特定的记录类型。

    最后,如果您想拒绝推送,除非用户在接收者活动中,您应该考虑使用前台调度系统。在这种情况下,您将完成从清单中删除所有NDEF_DISCOVERED意图过滤器,并用前台调度系统注册每个活动(接收者、发送者和主)。在接收者中,您将通过onNewIntent()接收NDEF消息。在发送者和主活动中,您只需忽略并删除任何收到的NDEF消息。有关示例,请参阅Android应用程序仅为一个活动启用NFC。

  •  类似资料:
    • 本文向大家介绍twitter-bootstrap 保持当前导航链接为“活动”,包括了twitter-bootstrap 保持当前导航链接为“活动”的使用技巧和注意事项,需要的朋友参考一下 示例            

    • 使用Appium(用于windows上的android),我需要检查登录场景,输入用户和密码后,点击登录按钮,新(等待)活动打开,1。请指导我如何获得当前活动,即在按下登录按钮之前。2.按下登录按钮后,如何导航到等待活动,以便检查登录是否成功。

    • 问题内容: 我正在使用POST方法。我需要创建一次,并且应该使用Keep Alive Connection。但是我认为,它每次都会建立一个新的连接。 因此,我需要使用 保持活动 连接。 这是我的代码段,很多帮助将不胜感激。 而且logcat日志是: 问题答案: 10:07:29.746:D / org.apache.http.headers(1529):>>连接:保持活动 您正在要求保持活动状态。

    • 我正在创建一个客户端服务器应用程序。服务器已经设计好,等待从客户端连接。现在在客户机部分中,我希望在应用程序的整个生命周期中保持连接活动,并且只有当主客户机应用程序关闭或关闭或者服务器关闭它时,连接才会关闭。 在处理程序中我有:

    • 因为我们知道progressdialog需要一个参数上下文或获取片段的活动,但在解除对话框后,它转到了另一个片段,我将其设置为mainactivity默认片段为homepage 这是我课堂上使用的方法

    • 我使用okhttp3和retrofit2来获取json文件。我尝试了所有方法来使用keep-Alive连接来使数据下载更快,但似乎没有任何效果。 我已经实现了拦截器,并添加了keep-alive头。但它似乎就是不想工作。有人能看看我的代码,告诉我我在这里做错了什么吗?这是我的代码: 我想在这里补充的一点是,我使用Glide从服务器加载图像,Glide似乎使用Keep-Alive设置安静很好,因为G