Process the data stream and create records in the background

I have created an application that does the following steps very well -

  • Connects to a remote device ( SPP

    ) using a Bluetooth socket.

  • Then listens on a stream from the remote Bluetooth device on a separate stream.

  • Then, when the data stream arrives, it passes the data stream to the handler for analysis.

  • When the data is parsed, a broadcast is sent and records are created in the database.

Now I want to add new functionality -

When the application is in the back margin and "connected" to the remote device, it needs to continue processing the data stream and creating records.

So, as soon as I connect the socket, I pass the result "associated" with the method onPostExecute()

.

IMPORTANT NOTE:

1) My work related to all sockets (socket connection, socket data parsing, data handler) is in a snippet.

2) After establishing a connection, the private class (Thread - ConnectedThread.java) in the fragment continues to listen to the InputStream

public class EntryFragment extends Fragment{
    //More fragment code here then this
    public class ConnectedThread extends Thread {

        public ConnectedThread(BluetoothSocket socket) {
            //code initialization stuff
        }

         public void run() {
             // Keep listening to the InputStream until an exception occurs
             while (true) 
             {
                    // Read from the InputStream
                    if(mmInStream.available() > 0)
                    {
                       bytes = mmInStream.read(buffer);

                       mHandler.obtainMessage(MESSAGE_READ, 
                       bytes, -1, buffer).sendToTarget();
                    }              
              }   
          }
     }

      

3) My handler that handles reading step 2

    case MESSAGE_READ:

     //Call to AsyncTask to do background processing of data
     new parseStream(getActivity()).execute();
    break;

      

4) I am connected, so do something from onPostExecute () from AsyncTask parseStream

 @Override
 protected void onPostExecute(Void result) {
 //Database related work here

 //Result is connected so listen to data if app goes to background after this state
 if(result.equals("connected")) 
 { 
      Log.i(TAG, "CONNECTED TO Remote Device!");
      Toast.makeText(getActivity(),"CONNECTED TO Remote  
      Device!",Toast.LENGTH_SHORT).show();

      //Do something when connected
      setSetting("STATUS", "Connected");

      // Start the thread to manage the connection and perform transmissions
      mConnectedThread = new ConnectedThread(socket);
      mConnectedThread.start();

      //Do I need to call Service here to handle data ?????
      Intent serviceIntent= new Intent(context, DataProcessService.class);               
      getActivity().startService(serviceIntent);
   }
 }

      

5) I called the service in step 4 with the intention that it will execute when the app goes into the background and process data. But then how will it link to the Fragment, because all my work is processing the data in the Fragment. Do I really need to process the data or should I call the broadcast receiver here as it can also be processed in the background?

+3


source to share


1 answer


I've worked on this quite a bit. I will share with you what works best in my experience.

-Dedicated bluetooth service, which runs its own separate process to handle continuous data streams.

-changing broadcasts when receiving and processing data; especially if these are fast and large data streams. This is a mistake I've made in the past when handling BT streams. What I figured out is that it may work fine for small volumes or slow streams, but broadcasts are very expensive and I have seen big performance improvements when replacing them with IPC (Over-the-Air Link Data Service) for transmission data to be processed on the UI thread.

-IPC, as mentioned earlier, is definitely the best way if you go for a dedicated bluetooth service. The idea is that you want to bind your Context to a service in order to send and receive messages. Documentation: http://developer.android.com/guide/components/bound-services.html#Messenger



-When the action / context is limited to a running service, set the interface so that the activity is logged against who the service should respond to. Thus, you will be transmitting any incoming data from the Bluetooth radio and sending activity messages with new data, avoiding nasty unnecessary broadcasts.

-I'm writing a quick, basic example (untested and not compiled) based on my thoughts and online examples (from the docs). Hope this is helpful

public class BluetoothService extends Service {

     //
     // API keys for the messages being passed across ui thread <-> service
     //
     static final int REGISTER_CLIENT = 3;
     static final int NEW_DATA = 2;
     static final int WRITE_DATA = 1;
     static final int CONNECT_BT = 0;

      // manages actual connection
      private BluetoothManager btManager;

      // who is activity and ready to receive messages? 
      private Messenger clientToReply;

      public int onStartCommand(Intent intent, int flags, int startId) { 

           btManager = new BluetoothManager(this);

           return START_STICKY;//makes sure the service keeps running and get back up if it gets terminated
      } 

     //
    // Send data back to your activity
    //
     public void sendDataToBoundClient(byte[] bytes) {
           Message msgToClient = new Message();
           msgToClient.what = NEW_DATA;

          Bundle bNewData = new Bundle();
          bNewData.putByteArray("newData", bytes);

          msgToClient.setData(bNewData);
          try {
                clientToReply.send(msgToClient); //send
            } catch (RemoteException e) {
                e.printStackTrace(); //couldn't send
            }
     }

     /**
      * Handles messages received from a bound Context
      */
     public class MessageHandler extends Handler {
       /* (non-Javadoc)
       * @see android.os.Handler#handleMessage(android.os.Message)
       */
        @Override
        public void handleMessage(Message msg) {

               switch (msg.what) {

                     case REGISTER_CLIENT: 
                         // now we know to whom to reply with our messages, callbacks or new data
                         clientToReply = msg.replyTo;
                         break;

                     case WRITE_DATA:
                         break;

                     case CONNECT_BT: 
                         // launches Connect & Connected Threads
                         // would follow the same pattern as in http://developer.android.com/guide/topics/connectivity/bluetooth.html#ConnectingAsAClient
                         btManager.connect(); 
                         break;
               }
        }
    }

}




 //
    // Check examples in http://developer.android.com/guide/topics/connectivity/bluetooth.html#ConnectingAsAClient
    //
    public class BluetoothManager {
        private ConnectThread connectThread; //thread to connect
        private ConnectedThread connectedThread; //thread manages connection

        private BluetoothService service;

        public BluetoothManager(BluetoothService service) {
             this.service = service;
        }

       //
       // stuff omitted...
       //

        public void connect() {
               connectThread = new ConnectThread();
               connectThread.start();
        }


       public void writeData(byte[] bytes) {
              connectedThread.write(bytes);
        }

       public void onDataRead(byte[] bytes) {
            // service knows how to forward this to the client (bound activity, for example)
            this.service.sendDataToBoundClient(bytes);
       }
    }

//
// Based on the example from http://developer.android.com/guide/components/bound-services.html#Messenger
//
public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

   // handle incoming messages
   protected Messenger messagesFromService = new Messenger(new IncomingHandler());

    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void registerAsClient() {
        if (!mBound) return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = new Message();
        msg.what = BluetoothService.REGISTER_CLIENT;
        msg.replyTo = messagesFromService; // reply to "me"!

        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }


    public class IncomingHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
                 switch (msg.what) {
                      case BluetoothService.NEW_DATA: 
                         Bundle data = msg.getData;
                         // handle your new data!
                         break;
                }
        }

    }

}
}
}

      

+2


source







All Articles