wervdon
wervdon

Reputation: 557

How to send messages from activity to service and execute them while the service is running?

I have an activity which starts an IntentService:

intent = new Intent(MyApplication.getAppContext(), MyService.class);
intent.putExtra("EXTRA_DEVICE_ADDRESS", value);
MyApplication.getAppContext().startService(intent);

The service starts a Bluetooth connection with the MAC address I sent.

device = mBluetoothAdapter.getRemoteDevice(macAddress);

public ConnectThread(BluetoothDevice device) {
    this.mmDevice = device;
    BluetoothSocket tmp = null;
    try {
        tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID));
    } catch (IOException e) {
        e.printStackTrace();
    }
    mmSocket = tmp;
}

I listen:

while (true) {
    try {
        if (mmInStream.available() != 0) {
            bytes = mmInStream.read(buffer);    
            String readMessage = new String(buffer, 0, bytes);
            sendMessageToActivity("incoming", readMessage);
        } else {
            SystemClock.sleep(100);
        }

And send received messages back to the activity:

public void sendMessageToActivity(String type, String message) {
    intent = new Intent(BROADCAST_ACTION);
    intent.putExtra(type, message);
    sendBroadcast(intent);
}

I use a BroadcastReceiver to receive messages from the service:

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        updateUI(intent);
    }
};

I call from the activity (part of the problem):

private void writeOut(final String message) {
    msg = message;
    byte[] send = msg.getBytes();
    MyService.write(send);
}

This is the service's static write() method:

public static void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (obj) {
        if (mState != STATE_CONNECTED)
            return;
        r = mConnectedThread;
    }
    // Perform the write unsynchronized
    r.write(out);`
}

My problem: All of the above works as intended except MyService.write(send). UI gets stuck. I tried to use an AsyncTask but it didn't work. I think I need to stop using that static write() method and send messages to the service and let him do the job. I believe I need to initialize a Handler in the activity, send it to the service by the intent via startService().

I want to keep track of the messages in and out from the service. It is working fine with incoming messages. I need to figure out a way to properly receive messages from the activity, execute them and then send information back to the activity.

Upvotes: 1

Views: 3942

Answers (1)

user1521536
user1521536

Reputation:

First, about IntentService:

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

So, consider moving your code to a Service. I'm not sure about Bluetooth connections and NetworkOnMainThreadException, but just in case: note that a Service runs on main UI thread, so to avoid of such exception, you will need something like Thread inside your service. Don't use AsyncTask, because AsyncTasks should ideally be used for short operations (a few seconds at the most.) Also note that the system will manage the service's lifecycle automatically, you shouldn't/ cannot interact with it in any static methods.

Now come back to your problem. The way you use broadcast receiver (to send messages from the service to the activity) is correct, but consider using ResultReceiver (available in API 3+). Using ResultReceiver is better than sending a wide broadcast message, I think. You can put a ResultReceiver into an Intent.

And to send messages from the activity to the service, I assume you moved to Service. You can put anything into an Intent and call startService() again to send it. You'll get the intent in onStartCommand(). Or if you have bound the service using this technique, you could call the service's methods directly from inside the activity.

There are some sample projects working with services in the SDK — folder [Android SDK]/samples/. On emulators, you can test those projects in the app named API Demos.

Upvotes: 3

Related Questions