传递给接收活动的多个扫描/意图

6
我有一个持续的问题,我的应用在NFC标签扫描后向接收Activity传递多个意图。
我的应用程序基本上会扫描一个带有一些数据的NFC标签并将其发送到服务器。通常情况下它工作得很好。我知道NFC在几厘米的范围内工作,并且也许我的问题是用户错误,例如用户在标签周围挥动手机,这可能会在毫秒内扫描两次。
我在应用程序对象中放置了一个计时器。当用户扫描标签时,我启动计时器并将标志设置为false,在处理NFC意图的Activity中检查该标志,如果标志为false,则放弃意图。这(应该)可以防止在10秒内多次扫描标签。
我的应用程序用于家庭护理工作,因此用户将在客户家中扫描标签。当他们第一次扫描标签时,它会记录他们在该客户端的登录时间和数据。第二次扫描标签将使他们退出登录。
总的来说,它工作得很好,但有时护理人员会在第一个客户端登录和退出,然后在第二个客户端或几小时后,护理人员将在先前的客户端重新登录。
我认为发生的事情是护理人员误扫了标签,这导致NFC适配器触发两次。第一个意图立即传递,然后几分钟/几小时后传递第二个。
事物的流程如下。 扫描标签->意图传递到Activity->启动AppObj计时器。 将数据写入sqlite DB->启动IntentService将交易发送到服务器(10秒后取消)。
有人能看出我错过了什么问题,可以解释为什么会在几个小时后传递重复的意图吗?
有人能提出一个解决方案来防止这种情况发生吗?
处理意图的活动是否存在问题?例如,在错误的Activity生命周期方法中使用了错误的代码?
有没有办法取消/拦截第二个误扫的意图?
基本上,我希望nfcAdapter可以在一秒钟内触发10次,但只有第一次扫描被传递到该Activity。我该如何实现这一点?
我将发布一些代码。
[编辑2]
Toast.makeText(this, "about to test flags", Toast.LENGTH_LONG).show();

        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {

            Toast.makeText(this, "intent is from history", Toast.LENGTH_LONG).show();

        }else{

            Toast.makeText(this, "intent is not from history", Toast.LENGTH_LONG).show();

        }

[编辑3]

<activity
            android:name=".NfcscannerActivity"
            android:screenOrientation="portrait"

            >
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:mimeType="text/plain" />
            </intent-filter>
            <intent-filter>
                <action android:name="com.carefreegroup.rr3.QRCODE_ACTION" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:mimeType="text/plain" />
            </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>

        <activity
            android:name=".EntryActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

            <intent-filter>
                <action android:name="com.carefreegroup.rr3.INVALID_CARER_TAG_SCANNED" />

                <category android:name="android.intent.category.DEFAULT" />


            </intent-filter>
        </activity>

. [edit4]

Tag tagTest = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

            Ndef ndefTag = Ndef.get(tagTest);

            try {
                Log.e(TAG, "about to test io operations on Ndef Tag");
                ndefTag.connect();  // this should already perform an IO operation and should therefore fail if there is no tag
                NdefMessage ndefMsg = ndefTag.getNdefMessage(); // this reads the current NDEF message from the tag and consequently causes an IO operation
                Log.e(TAG, "tested io operations on Ndef Tag, must be a real Tag!!!!!******!!!!!!");
            } catch (Exception e) {
                // there is no tag or communication with tag dropped
                Log.e(TAG, "tested io operations on Ndef Tag, No Tag there, must be a re-delivery of the old Tag via an intent!!!!!******!!!!!!!!!!!!!!!!!!!!!!");
                onResume();
            } finally {
                try {
                    ndefTag.close();
                } catch (Exception e) {
                }
            }

你的代码没有太多意义(不平衡的括号,} else { Log.e(TAG, "ndef not discovered!!!!!!"); } 没有匹配的 if ... {)。请发布你正确(并且格式正确)的代码。 - Michael Roland
另外,你是只在onCreate中处理意图还是也会在onStartonResume中进行处理? - Michael Roland
@Michael Roland 你好,我已经发布了我的onCreate()方法中与NFC相关的全部内容。我只在onCreate方法中处理意图。 - turtleboy
2个回答

5
根据您的描述,我认为您受影响的用户通过按下主页键“关闭”(实际上是隐藏)应用程序。稍后,他们将从历史记录(长按主页键)打开该应用程序(或者说是打开该活动)。
假设你onCreate()中处理与NFC相关的意图仅限于,当从后台唤起Activity时一般不会遇到你所描述的问题,因为如果你的Activity仍然存在于后台,就不会调用onCreate()方法。但是,如果您的Activity在此期间被销毁(例如手动杀死应用程序、系统杀死应用程序以释放资源等),则从历史记录重新启动应用程序将导致您的onCreate()方法再次运行。由于Android在打开应用程序时重建Activity堆栈并重新发送原始意图(即最初启动Activity的意图),因此当打开应用程序时,您的Activity将接收到它最初启动时收到的NFC意图。
您可以通过检查接收到的意图是否设置了FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY来解决此问题。这种情况仅限于如果您的Activity是从历史记录中启动的。
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
     if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
         NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
        ...
    }
}

在解决你的初始问题之前,最后的办法是,请记住NFC标签可以在接收到意图后通过IO操作访问。因此,为了检查接收到的标签是否存在,您可以执行此类IO操作。

例如,如果您的标签是NDEF标签:

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndefTag = Ndef.get(tag);

try {
    ndefTag.connect();  // this should already perform an IO operation and should therefore fail if there is no tag
    NdefMessage ndefMsg = ndefTag.getNdefMessage();  // this reads the current NDEF message from the tag and consequently causes an IO operation
} catch (Exception e) {
    // there is no tag or communication with tag dropped
} finally {
    try {
        ndefTag.close();
    } catch (Exception e) {
    }
}

对于非NDEF标签,您需要了解如何使用低级命令访问标签。但至少连接测试可适用于任何标签。


@turtleboy 我已经更新了我的答案,为您提供了一种方法来帮助您检测是否收到了当前意图或旧意图(其中导致它的标签不存在)。然而,那种方法绝对不是一个理想的解决方案。 - Michael Roland
@MichaelRoland 感谢您提供的代码!您认为只使用检测意图是新的还是旧的代码就足够了吗?还是应该将该代码与 Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 检查和在清单中设置 android:clearTaskOnLaunch=true 结合使用? - turtleboy
@MichaelRoland 实际上我刚刚使用了[edit4]中的代码。当我扫描标签时,它似乎跳转到代码的异常部分。尽管try/catch在扫描标签时失败了。你有什么想法吗? - turtleboy
@turtleboy 很好,你应该能够进行相当通用的存在检测(对于NDEF情况使用Ndef上的连接,对于TECH情况使用NfcA/NfcB/NfcF/NfcV(或仅使用实际使用的那些)。 - Michael Roland
@MichaelRoland 仅澄清一下,您是否认为2.3.6可以处理NFC或Android堆栈(重新传递旧意图)与4.x不同,因此应该对我的一个客户(运行2.3.6的客户)遇到的问题负责? - turtleboy
显示剩余26条评论

0

向接收活动传递多个扫描/意图

已经接受答案,但更好的选择是

在启动活动时添加以下标志(默认情况下,活动以默认模式启动,即启动活动的新实例) FLAG_ACTIVITY_CLEAR_TOP


你应该意识到 NFC 相关的 Intent 是由 Android 系统生成的,而且无法向这些 Intent 添加标志。 - Michael Roland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接