2017-08-09 10 views
2

正常に動作していると思われ、NFC経由でデータを完全に送信できるアプリケーションがあります。私は主な活動、データを送信する活動、およびデータを受け取るための異なる活動を持っています。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> 

は、送信者のクラスである:ここで

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()); 
    } 
} 

は、レシーバクラスです:

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()); 
    } 
} 
+0

あなたの問題は 'singleTask'起動モードによるものと推測しています。なぜそれを指定したのですか?アプリのナビゲーションを説明してください。 –

+0

また、 'NDEF_DISCOVERED'アクションを処理できる2つのアクティビティがあります。これは、NFCタグをスキャンするときにAndroidがどちらを起動するのかわからないことを意味します。これはどうやって扱いますか? –

答えて

0

あなたはあなたの中にQUTEいくつかの問題を持っています送信者アクティビティのコード:

  1. あなたはmessagesToSendArrayを保存しますが、実際にはこの配列リストにはデータは入れません。 messagesToSendArray.size()は常に0です)。 createNdefMessage()が呼び出されるたびにNDEFメッセージを新しく作成するので、messagesToSendArrayを保存して復元する必要はありません。

  2. NDEFメッセージを1つのアクティビティに送信したいが、別のアクティビティでNFCイベントを受信するとします。ただし、送信者アクティビティを登録して、マニフェストにNDEF_DISCOVEREDイベントを受信して​​います。これらのイベントを受信して​​処理したくない場合は、マニフェストにNDEF_DISCOVEREDインテントフィルタは必要ありません。

  3. また、あなたの送信者の活動にNDEF_DISCOVEREDの意図を処理する必要がない(つまり、あなたは安全な方法onNewIntent()handleNfcIntent()を削除することができます)。

  4. Androidバージョンでは、Jelly Beanの下に無効な構造のNFC Forum Textレコードが作成されます。テキストRTDフォームで符号化されたペイロードをrequres(参照this postStatus長さTextがUTF-8でエンコードされている場合Language CodeLanguage Codenに等しい

     
    +----------+---------------+--------------------------------------+ 
    | Status | Language Code | Text         | 
    | (1 byte) | (n bytes)  | (m bytes)       | 
    +----------+---------------+--------------------------------------+ 
    
    「EN」IANA言語コード(例えばためであります英語)。したがって、そのレコードをエンコードする適切な方法は、次のようになります。

    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); 
    } 
    
  5. あなたはジェリービーン以下のAndroidバージョンでNFCフォーラムのテキストレコードを作成するなぜあなたは上記のジェリービーンとのMIMEタイプレコードを作成しながら、それは私には不明です。あなたは一貫して、すべてのプラットフォームで同じレコード型を作成する必要があります(Method NdefRecord.createTextRecord("en" , "string") not working below API level 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); 
    } 
    
  6. 最後に、createRecords()にあなたはその結果

    NdefRecord[] records = new NdefRecord[1]; 
    

    として配列recordsを作成し、配列は、一つの要素を持っていますインデックス0にアクセス可能です。

    records[1] = record; 
    

    これはIndexOutOfBounds例外が発生:Hoeverは、後で上の要素1にアクセスしてみてください。 createRecords()createNdefMessage()コールバックを使用してAndroidから呼び出されるため、コールバックは失敗します(実行時例外のため)。AndroidはNDEFメッセージを使用しません。代わりに、AndroidはあなたのアプリにデフォルトのNDEFメッセージを使用します。このデフォルトのNDEFメッセージには、メインのアクティビティが呼び出されるAndroidアプリケーションレコードが含まれています(他のアクティビティのいずれも、デフォルトのNDEFメッセージの特定のコンテンツに対して開始するように登録されていないため)。 NFC tag detection is not calling onNewIntent and it's Launching From Main Activityを参照してください。その結果、あなたは0に新たに作成したNDEFレコードを保存recordsにオフセットを変更する必要があります:

    records[0] = record; 
    

    また、あなたは、これはその後、以前に上書きするので、ライン

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

    を削除する必要がありますAndroidアプリケーションレコードを使用してインデックス0に保存されたNDEFレコード(messagesToSendArray.size()は0)。この場合も、マニフェストの特定のレコードタイプに登録していないため、メインアクティビティが開始されます。あなたは、ユーザーが受信アクティビティ内でない限りプッシュを拒否したい場合

最後に、あなたは、フォアグラウンドディスパッチシステムを使用して検討すべきです。その場合、マニフェストからすべてのNDEF_DISCOVEREDインテントフィルタを削除し、代わりに各アクティビティ(受信者、送信者、およびメイン)をフォアグラウンドディスパッチシステムに登録します。受信者では、onNewIntent()を介してNDEFメッセージを受信します。送信者と主なアクティビティでは、受信したNDEFメッセージを無視して削除するだけです。例については、Android app enable NFC only for one Activityを参照してください。

関連する問題