在 Android 应用中同时使用 QR 和 NFC 技术

Using QR and NFC technology together in an Android app

目前我正在开发一个包含两个活动的 Android 应用程序。第一个 activity (MainActivity) 在启动应用程序或扫描二维码时启动。当用户按下按钮时,MainActivity 启动第二个 activity (NFCActivity)。 NFCActivity等待用户点击一个NFC token,从token中读取数据,returns将读取的数据发送到MainActivity.

如果应用程序是手动启动的,这会很好地工作。如果应用程序是通过扫描二维码启动的,点击 NFC 标签不会像预期那样调用 NFCActivity 的 onNewIntent() 方法,而是在顶部创建一个新的 NFCActivity 实例已经显示的那个。

调用了enableForegroundDispatch()方法,应该设置FLAG_ACTIVITY_SINGLE_TOP。下面提供了一个最小示例的相关源代码。任何帮助将不胜感激!

主要Activity:

public class MainActivity extends Activity {

    private EditText dataRead;

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

        dataRead = (EditText) findViewById(R.id.data);

        final Button readKeyButton = (Button) findViewById(R.id.readNFC);
        readKeyButton.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {

                Intent keyIntent = new Intent(MainActivity.this,
                    NFCActivity.class);
                keyIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

                startActivityForResult(keyIntent, 1);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
        Intent intent) {

        if (requestCode == 1) {

            String result =     intent.getExtras().getString("resultData");
        this.dataRead.setText(result);
        }
    }
}

主要 Activity 的 GUI:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/readNFC"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="127dp"
        android:text="Read NFC Tag" />

    <EditText
        android:id="@+id/data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/readNFC"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="85dp"
        android:ems="10" >

        <requestFocus />
    </EditText>

</RelativeLayout>

NFCActivity:

public class NFCActivity extends Activity {

    private NfcAdapter mAdapter;
    private PendingIntent pendingIntent;
    private IntentFilter[] mFilters;
    private String[][] mTechLists;  


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

        mAdapter = NfcAdapter.getDefaultAdapter(this);
        pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
                getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

        // // Setup an intent filter for all MIME based dispatches
        IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            ndef.addDataType("*/*");
        } catch (MalformedMimeTypeException e) {
            throw new RuntimeException("fail", e);
        }
        IntentFilter td = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
        mFilters = new IntentFilter[] { ndef, td };
        //
        // // Setup a tech list for all NfcF tags
        mTechLists = new String[][] { new String[] { NfcV.class.getName(),
                NfcF.class.getName(), NfcA.class.getName(),
                NfcB.class.getName() } };

    }


    @Override
    public void onResume() {

        super.onResume();
        if (mAdapter != null)           
            mAdapter.enableForegroundDispatch(this, pendingIntent, mFilters,
                    mTechLists);
    }

    @Override
    public void onPause() {

        super.onPause();
        if (mAdapter != null)
            mAdapter.disableForegroundDispatch(this);
    }

    @Override
    public void onNewIntent(Intent intent) {

        Log.d("TEST", "onNewIntent() called.");

        // READ THE NFC TAG HERE [SKIPPED FOR MINIMAL EXAMPLE]

        // Return dummy data for test
        Intent result = new Intent();
        result.putExtra("resultData", "DUMMY DATA");

        setResult(1, result);
        finish();
    }   


}

NFCActivity 的 GUI:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#303030"
    android:paddingLeft="30dp"
    android:paddingRight="30dp" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Tap your NFC tag.."
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="#FF8811"
        android:textSize="30sp"
        android:textStyle="bold" />

</RelativeLayout>

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.nfcqrtest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="18" />

    <uses-permission android:name="android.permission.NFC" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="test.nfcqrtest.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="myapp" android:host="test.org" android:pathPrefix="/testapp" />
            </intent-filter>            

        </activity>

        <activity
            android:name=".NFCActivity"
            android:windowSoftInputMode="stateHidden" android:screenOrientation="portrait" android:launchMode="singleTop">
        </activity>

    </application>

</manifest>

以防有人遇到类似问题:我终于能够通过将 MainActivityandroid:launchMode 属性 设置为 singleInstance 来解决上述问题.