首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >接收NFC的应用程序总是在前面弹出新实例。

接收NFC的应用程序总是在前面弹出新实例。
EN

Stack Overflow用户
提问于 2016-06-08 12:28:19
回答 1查看 1.7K关注 0票数 1

通过启动器启动应用程序时,我运行以下生命周期:

代码语言:javascript
复制
onCreate..., onPostCreate...,  onResume..., onNewIntent..., act:android.intent.action.MAIN, mNfcAdapter.disableForegroundDispatch OK.

然后,当我点击一个标记时,当我运行以下生命周期时,似乎启动了一个新的应用程序实例:

代码语言:javascript
复制
onPause..., onCreate..., onPostCreate...,  onResume..., onNewIntent..., act:android.nfc.action.TAG_DISCOVERED, myTag.mId:048a1382bd2384)

由于我试图使用前台调度系统来禁用接收NFC事件,所以我希望我的应用程序忽略NFC标记。那么,为什么我的活动被重新创造了呢?是因为AndroidManifest.xml允许它吗?

代码语言:javascript
复制
package com.example.pdf.nfcaccess;

import android.annotation.SuppressLint;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;

// PDf import
import android.telephony.TelephonyManager;
import android.content.Intent;
import android.content.Context;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Log;
import android.nfc.tech.NfcF;
import android.nfc.Tag;

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 */
public class FullscreenActivity extends AppCompatActivity {
    /**
     * Whether or not the system UI should be auto-hidden after
     * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
     */
    private static final boolean AUTO_HIDE = true;

    /**
     * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
     * user interaction before hiding the system UI.
     */
    private static final int AUTO_HIDE_DELAY_MILLIS = 3000;

    /**
     * Some older devices needs a small delay between UI widget updates
     * and a change of the status and navigation bar.
     */
    private static final int UI_ANIMATION_DELAY = 300;
    private final Handler mHideHandler = new Handler();
    private View mContentView;
    private final Runnable mHidePart2Runnable = new Runnable() {
        @SuppressLint("InlinedApi")
        @Override
        public void run() {
            // Delayed removal of status and navigation bar

            // Note that some of these constants are new as of API 16 (Jelly Bean)
            // and API 19 (KitKat). It is safe to use them, as they are inlined
            // at compile-time and do nothing on earlier devices.
            mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        }
    };
    private View mControlsView;

    // application
    static FullscreenActivity mInstance;

    NfcAdapter mNfcAdapter;
    Intent mNfcIntent;
    PendingIntent mNfcPendingIntent;
    IntentFilter mTagIntentFilter;
    IntentFilter[] mIntentFiltersArray;
    String[][] mTechLists;
    TextView mTagContentText;

    // log
    //java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
    java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
    android.widget.ArrayAdapter<String> mLogAdapter;
    android.widget.ListView mLogList;

    /**/
    private final Runnable mShowPart2Runnable = new Runnable() {
        @Override
        public void run() {
            // Delayed display of UI elements
            ActionBar actionBar = getSupportActionBar();
            if (actionBar != null) {
                actionBar.show();
            }
            mControlsView.setVisibility(View.VISIBLE);
        }
    };
    private boolean mVisible;
    private final Runnable mHideRunnable = new Runnable() {
        @Override
        public void run() {
            hide();
        }
    };
    /**
     * Touch listener to use for in-layout UI controls to delay hiding the
     * system UI. This is to prevent the jarring behavior of controls going away
     * while interacting with activity UI.
     */

    /* Enable NFC
     */
    private final View.OnTouchListener mFuncNfcEnable = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                traceTry("mFuncNfcEnable");
                if (mNfcAdapter != null) {
                    try {
                        traceTry("mNfcAdapter.enableForegroundDispatch");
                        mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
                        traceOk();
                    }
                    catch (Throwable t) {
                        traceFails(t);
                    }
                }
            }
            return false;
        }
    };

    /* read Intent
     */
    private final View.OnTouchListener mFuncNfcRead = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (mNfcAdapter != null) {
                try {
                    traceTry("onNewIntent");
                    onNewIntent(getIntent());
                    traceOk();
                }
                catch (Throwable t) {
                    traceFails(t);
                }
            }
            return false;
        }
    };

    /* Disable NFC
     */
    private final View.OnTouchListener mFuncNfcDisable = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                traceTry("mFuncNfcDisable");
                if (mNfcAdapter != null) {
                    try {
                        traceTry("mNfcAdapter.disableForegroundDispatch");
                        mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
                        traceOk();
                    }
                    catch (Throwable t) {
                        traceFails(t);
                    }
                }
            }
            return false;
        }
    };

    /* Quit
     */
    private final View.OnTouchListener mFuncBtnQuit = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            finish();
            return false;
        }
    };

    /**/
    private void trace(String m) {
        Log.d("NFCTags",m);
        /*TextView tv = (TextView)findViewById(R.id.logContent_value);
        String previous = tv.getText().toString();
        tv.setText(previous + "\n" + m);*/
        if (mLogAdapter != null) {
            mLogItems.add(m);
            mLogAdapter.notifyDataSetChanged();
            mLogList.setSelection(mLogList.getCount()-1);
        }
    }

    String mMessage = "";
    private void traceTry(String m) {
        trace(m + "...");
        mMessage = m;
    }

    private void traceOk() {
        trace(mMessage + " OK");
        mMessage = "";
    }

    private void traceFails(Throwable t) {
        String msg = mMessage + " fails";
        if (t != null) {
            msg += " exception:" + t.getMessage();
        }
        trace(msg);
        //Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
        mMessage = "";
    }

    /*
        */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        trace("onCreate...");

        // set global unique instance
        FullscreenActivity.mInstance = this;

        setContentView(R.layout.activity_fullscreen);

        // log
        mLogItems.add("starts");
        mLogAdapter = new android.widget.ArrayAdapter<String>(this, R.layout.support_simple_spinner_dropdown_item, mLogItems);
        mLogList = (android.widget.ListView) findViewById(R.id.logList_value);
        mLogList.setAdapter(mLogAdapter);

        mVisible = true;
        mControlsView = findViewById(R.id.fullscreen_content_controls);
        mContentView = findViewById(R.id.fullscreen_content);
        mTagContentText = (TextView) findViewById(R.id.tagContent_value);

        // Set up the user interaction to manually show or hide the system UI.
        mContentView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toggle();
            }
        });

        // Upon interacting with UI controls, delay any scheduled hide()
        // operations to prevent the jarring behavior of controls going away
        // while interacting with the UI.

        findViewById(R.id.nfcRead_btn).setOnTouchListener(mFuncNfcRead);

        //findViewById(R.id.nfcDisable_btn).setOnTouchListener(mFuncNfcDisable);

        findViewById(R.id.quit_btn).setOnTouchListener(mFuncBtnQuit);

        trace("onCreate > before initializing nfc");

        TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
        trace("ID:" + tm.getDeviceId());
        trace("Network Operator Name:" + tm.getNetworkOperatorName());
        trace("Sim Operator Name:" + tm.getSimOperatorName());
        trace("Sim Serial Number:" + tm.getSimSerialNumber());
        trace("Phone Type:" + tm.getPhoneType());
        trace("Initial Phone Number:" + tm.getLine1Number());

        boolean tryNfc = true;

        if (tryNfc) {

            try {
                mMessage = "NfcAdapter.getDefaultAdapter";
                mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
                if (mNfcAdapter == null) {
                    mMessage = "NFC is not available";
                    traceFails(null);
                    return;
                } else {
                    traceOk();
                }
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            // Check if NFC is enabled
            try {
                mMessage = "test NfcAdapter.isEnabled";
                if (!mNfcAdapter.isEnabled()) {
                    mMessage = "NFC is not enabled. do it manually";
                    traceFails(null);
                    return;
                } else {
                    trace("NFC is enabled.");
                }
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            try {
                mMessage = "create new Intent";
                mNfcIntent = new Intent(this, getClass());
                traceOk();
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            try {
                mMessage = "mNfcIntent.addFlags, PendingIntent.getActivity";
                mNfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                mNfcPendingIntent = PendingIntent.getActivity(this, 0, mNfcIntent, 0);
                traceOk();
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            try {
                mMessage = "new IntentFilter";
                mTagIntentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
                mTagIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
                traceOk();
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            try {
                mMessage = "addDataType, new IntentFilter[]";
                mTagIntentFilter.addDataType("*/*");
                //mTagIntentFilter.addDataType("text/plain");
                mIntentFiltersArray = new IntentFilter[]{mTagIntentFilter};
                traceOk();
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            // Setup a tech list for all NfcF tags
            try {
                mMessage = "new tech list";
                //mTechLists = new String[][]{new String[]{NfcF.class.getName()}};
                mTechLists = new String[][]{};
                traceOk();
            } catch (Throwable t) {
                traceFails(t);
                return;
            }

            /*
            if (mNfcAdapter != null) {
                try {
                    mMessage = "mNfcAdapter.enableForegroundDispatch";
                    mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
                    traceOk();
                }
                catch (Throwable t) {
                    traceFails(t);
                }
            }
            */
        }
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        trace("onPostCreate...");

        // Trigger the initial hide() shortly after the activity has been
        // created, to briefly hint to the user that UI controls
        // are available.
        //delayedHide(100);
    }

    private void toggle() {

        trace("toggle...");

        if (mVisible) {
            hide();
        } else {
            show();
        }
    }

    private void hide() {

        trace("hide...");

        // Hide UI first
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
        mControlsView.setVisibility(View.GONE);
        mVisible = false;

        // Schedule a runnable to remove the status and navigation bar after a delay
        mHideHandler.removeCallbacks(mShowPart2Runnable);
        mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
    }

    @SuppressLint("InlinedApi")
    private void show() {
        // Show the system bar
        mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        mVisible = true;

        // Schedule a runnable to display UI elements after a delay
        mHideHandler.removeCallbacks(mHidePart2Runnable);
        mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
    }

    /**
     * Schedules a call to hide() in [delay] milliseconds, canceling any
     * previously scheduled calls.
     */
    private void delayedHide(int delayMillis) {
        mHideHandler.removeCallbacks(mHideRunnable);
        mHideHandler.postDelayed(mHideRunnable, delayMillis);
    }

    /**/
    public String intentToText(Intent intent){

        String report = "?";
        try {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                java.util.Set<String> keys = bundle.keySet();
                java.util.Iterator<String> it = keys.iterator();
                report = "Intent:{";
                while (it.hasNext()) {
                    String key = it.next();
                    report += "\n[" + key + ":" + bundle.get(key) + "],";
                }
                report += "}\n";
            }
        }
        catch(Throwable t){
            trace("intentToText > " + t.getMessage());
        }
        return report;
    }

    /**/
    public static String byteArrayToHex(byte[] a) {
        StringBuilder sb = new StringBuilder(a.length * 2);
        for(byte b: a)
            sb.append(String.format("%02x", b & 0xff));
        return sb.toString();
    }

    /**/
    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        trace("onNewIntent...");

        handleIntent(intent);
    }

    /**/
    void handleIntent(Intent intent) {

        if (intent == null) return;

        String sAction = intent.getAction();
        trace("act:" + sAction);

        if( (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
            ||  (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction()))
            ||  (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()))) {

            String payload = intent.getDataString();

            mTagContentText.setText("act:" + sAction + "\n" + "pload:" + payload + "\n" + intentToText(intent));

            Tag myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            if (myTag != null) {
                trace("myTag.mId:" + byteArrayToHex(myTag.getId()));
                mTagContentText.setText(mTagContentText.getText() + "\n" + "myTag.mId:" + byteArrayToHex(myTag.getId()));

                android.os.Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
                if (rawMsgs != null) {
                    for (android.os.Parcelable p : rawMsgs) {
                        NdefMessage msg = (NdefMessage) p;
                        NdefRecord[] records = msg.getRecords();
                        for (NdefRecord record : records) {
                            short tnf = record.getTnf();
                            byte[] id = record.getId();
                            byte[] payLoad = record.getPayload();
                        }
                    }
                }
            }
        }

    }

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

        trace("onResume...");
        if (mNfcAdapter != null) {
            try {
                // See if the Activity is being started/resumed due to an NFC event and handle it
                onNewIntent( getIntent());
            }
            catch (Throwable t) {
                traceFails(t);
            }

            try {
                mMessage = "mNfcAdapter.disableForegroundDispatch";
                mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
                traceOk();
            }
            catch (Throwable t) {
                traceFails(t);
            }
        }
    }

    /**/
    @Override
    protected void onPause() {
        super.onPause();

        trace("onPause...");
    }
}

AndroidManifest.xml是:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.pdf.nfcaccess">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_pdflauncher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:debuggable="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".FullscreenActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:theme="@style/FullscreenTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

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

            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

    <!--intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain"/>
    </intent-filter-->

</manifest>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-08 16:50:26

您接收NFC意图(操作TAG_DISCOVERED),因为您在清单中注册了它:

代码语言:javascript
复制
<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

这也是你的活动在接收到意图后被重新创建的原因。

您为前景分配注册的意图筛选器(带有任何MIME类型的动作NDEF_DISCOVERED )似乎与您的标记不匹配(或者您还没有调用启用前景调度的代码段)。

请注意,调用disableForegroundDispatch()将禁用以前通过enableForegroundDispatch()注册的前台调度。它不会影响你清单中的意图过滤器。关于如何选择性地禁用清单中注册的意图筛选器,请参见Android: Can I enable/disable an activity's intent filter programmatically?。但是,关于NFC意图,您可能希望通过前台调度系统注册以接收所有标记的事件,然后在onNewIntent()中接收事件时选择性地忽略您不想要的标记。

关于您的代码的更多内容(实际上只涉及NFC部分)

  1. 对于清单中的NDEF_DISCOVERED意图筛选器,您通常还希望指定一个与标记的数据类型匹配的<data ... />元素。
  2. 不要在清单中使用TAG_DISCOVERED意图筛选器(除非您真正理解并希望了解它的影响)。TAG_DISCOVERED意图过滤器(当在清单中使用时)仅仅是APILevel9(在Android2.3.3之前)的兼容模式,而NFC支持非常非常有限,并且可以用来创建处理任何其他应用程序不支持的NFC标记的应用程序。
  3. 为了匹配任何标记,TECH_DISCOVERED意图筛选器需要一个技术列表XML文件。因此,清单中当前版本的此筛选器将永远不会匹配任何内容。
  4. disableForegroundDispatch()中调用onResume()没有任何意义。根据设计,在活动生命周期的这一点上,永远无法启用前台调度。这样做的原因是,您不能在enableForegroundDispatch()之前调用onResume(),并且必须最迟在onPause()中调用disableForegroundDispatch()
  5. 事实上,在enableForegroundDispatch() / onPause()以外的任何地方使用onResume() /onPause()都是没有意义的。如果您想停止侦听其他事件(例如按下按钮)上的标记,您只需在某些标志中记住当前状态(进程/不处理NFC事件),并且当您在onNewIntent()中接收到新的NFC意图时,您将处理或忽略基于该标志的标记。
  6. 您的代码不应该手动调用活动生命周期方法(就像您目前对onNewIntent(getIntent());所做的那样)。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37702519

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档