Search code examples
androidmultithreadinguser-interfacenfcndef

Read NFC tag until it is detached and update the UI while reading the tag


I want to read an NFC tag until the device moves away from the NFC tag. Then I want to do some activities. I have managed to do this using a while loop to read the tag and catching the InterruptedException. And I also want to update the UI while reading the tag inside the while loop. I couldn't find a way to update the UI when I'm in the while loop.

The data to update the UI comes from an onLocationChanged-listener.

public void onLocationChanged(Location location) {
    if (location.hasSpeed()) {
        /*double speed=location.getSpeed() * 3.6;;
        while (1==1)
        {*/
        speed = location.getSpeed() * 3.6;
        String units="km/h";
        s= new SpannableString(String.format(Locale.ENGLISH, "%.0f %s", speed, units));
        s.setSpan(new RelativeSizeSpan(0.45f), s.length()-units.length()-1, s.length(), 0);
        updateUI();

    }
}

public void updateUI(){
    drivingMode=findViewById(R.id.txtDriving);
    currentSpeed = findViewById(R.id.valSpeed);
      if (currentSpeed!=null) {
        currentSpeed.setText(s);
        if (speed > 10) {
            drivingMode.setText(R.string.msg_driving);
            isDriving = true;
        } else {
            drivingMode.setText(R.string.msg_notDriving);
            isDriving=false;
        }
    }
}

private void readFromNFC( Ndef ndef)  {
            try
            {
                ndef.connect();
                NdefMessage ndefMessage = ndef.getNdefMessage();
                ndef.close();
                String message = new String(ndefMessage.getRecords()[0].getPayload());
                // Log.d(TAG, "readFromNFC Before Pass: " + message);
                //Toast.makeText(this, "Text" + message, Toast.LENGTH_LONG).show();
                if (message.equals("in")) {
                    Toast.makeText(this.getApplicationContext(), R.string.message_nfc_holder_detected, Toast.LENGTH_LONG).show();
                    if (isDialogshowing) {
                        dialog.dismiss();
                        isEmergency=false;
                    }
                    while (1 == 1) {
                        ndef.connect();
                        ndefMessage = ndef.getNdefMessage();
                        message = new String(ndefMessage.getRecords()[0].getPayload());
                        //Log.d(TAG, "readFromNFCPassed: " + message);
                        TimeUnit.SECONDS.sleep(1);
                        ndef.close();
                        updateUI();
                    }

                } else {
                    Toast.makeText(this.getApplicationContext(), R.string.message_nfc_holder_error, Toast.LENGTH_LONG).show();
                    ndef.close();
                }

            } catch (IOException | FormatException | InterruptedException e ) {
                e.printStackTrace();
                Toast.makeText(this.getApplicationContext(), R.string.message_nfc_holder_detached, Toast.LENGTH_LONG).show();
                if(isDriving) {
                    activateEmergency();
                }
                else
                {
                    if (isDialogshowing) {
                        dialog.dismiss();
                        dialog.dismiss();
                        isDialogshowing = false;
                    }

                }
            }
}

Solution

  • In order to continuously read the UI thread without blocking the main UI thread, you could use an AsyncTask. This also allows you to publish status updates to the UI (thread) using an onProgressUpdate() callback.

    You AsyncTask could look something like this:

    private class ProcessNFCTask extends AsyncTask<Ndef, NdefMessage, Void> {
        protected Void doInBackground(Ndef... tag) {
            // This happens on the worker thread!
    
            // TODO: content of readFromNFC(Ndef ndef);
            // Instead of calling updateUI(), you would call publishProgress(message).
            // You can use whatever represents your progress instead of "message".
            // Instead of doing your finalization stuff (what you currently have
            // in the catch clause) here, you would want to do that in
            // onPostExecute() instead.
        }
    
        protected void onProgressUpdate(NdefMessage... progress) {
            // This happens on the UI thread!
    
            // You may also use the progress status information provided in
            // "progress" here. This is what you pass to publishProgress(...).
            updateUI();
        }
    
        protected void onPostExecute(Void result) {
            // This happens on the UI thread!
    
            // TODO: Whatever you want to do when you are finished reading, e.g.:
            if (isDriving) {
                activateEmergency();
            } else {
                if (isDialogshowing) {
                    dialog.dismiss();
                    dialog.dismiss();
                    isDialogshowing = false;
                }
            }
        }
    

    }