androidbroadcastreceiverlocalbroadcastmanager

BroadcastReceiver - Can't get button to change background


I have an Activity and a Service.

In my Activity, a button interacts with the Service to start/stop GPS logging.

My Service has 3 state indicators: One for being connected to Google Play Services, one for actively logging GPS, and one for processing what was logged.

When connected to Google Play Services the Service flow is this:

Ready -> Logging -> Processing -> Ready

The Service will broadcast these states as follows:

private void UpdateStatusBroadcast() {
    //Save status variables to intent
    Intent intent = new Intent(this.getString(R.string.BroadcastStatusIntent));
    intent.putExtra(getString(R.string.BroadcastIsConnected), mIsConnected);
    intent.putExtra(getString(R.string.BroadcastIsTripActive), mIsTripActive);
    intent.putExtra(getString(R.string.BroadcastIsProcessing), mIsProcessing);

    //Send the broadcast
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

My Activity receives the states as follows:

private class StatusReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        mIsConnected = intent.getBooleanExtra(getString(R.string.BroadcastIsConnected), false);
        mIsTripActive = intent.getBooleanExtra(getString(R.string.BroadcastIsTripActive), false);
        mIsProcessing = intent.getBooleanExtra(getString(R.string.BroadcastIsProcessing), false);

        HandleConnectionStatus();
        HandleTripStatus();
    }
}

Then comes my problem. In HandleTripStatus(), posted below, i change the text and background of a button to reflect what the Service is currently doing. This works fine for the first and the third case. I never see the second background drawn however, in spite of receiving the correct boolean values.

private void HandleTripStatus() {
    Button tripButton = (Button) findViewById(R.id.TripButton);
    Button liveMapButton = (Button) findViewById(R.id.LiveMapButton);

    if (mIsTripActive) {
        tripButton.setText(R.string.TripButtonTitleStop);
        tripButton.setBackground(ContextCompat.getDrawable(mContext, R.drawable.trip_button_stop_shape));
        liveMapButton.setEnabled(true);
    } else if (mIsProcessing) {
        tripButton.setText(R.string.TripButtonTitleStopping);
        tripButton.setBackground(ContextCompat.getDrawable(mContext, R.drawable.trip_button_stopping_shape));
        liveMapButton.setEnabled(false);
    } else {
        tripButton.setText(R.string.TripButtonTitleStart);
        tripButton.setBackground(ContextCompat.getDrawable(mContext, R.drawable.trip_button_start_shape));
        liveMapButton.setEnabled(false);
    }
}

To debug the issue i verified the following:

Some other code that could possibly be relevant:

This is how the Activity requests that the GPS logging should stop (Leading to the processing step before finishing)

private void EndTrip() {
    //Create message to TripService with intent to run case for END_TRIP
    Message message = Message.obtain(null, TripService.END_TRIP, 0, 0);

    //Send the Message to the Service
    try {
        mMessenger.send(message);
        Toast.makeText(mContext, R.string.TripStopToast, Toast.LENGTH_SHORT).show();
    } catch (RemoteException e) {
        Log.e("Debug", "Failed to contact TripService");
    }
}

This is the structure of what happens in the Service after receiving the message from the Activity.

private void EndTrip() {
    //Stop retrieving location updates

    //Broadcast the updated status and begin processing the trip
    mIsTripActive = false;
    mIsProcessing = true;
    UpdateStatusBroadcast();

    //Processing the collected data

    //Finish up
    mIsProcessing = false;
    UpdateStatusBroadcast();
    stopForeground(true);
}

I am all out of ideas. What can the cause be? Why does the button background not change in the else-if?


Solution

  • After too many hours of trial and error, I found the cause to be thread-related.

    What I learned:

    Note that this of course broke the broadcasts i relied on. This was however easy to fix; The consequence is that I can no longer use LocalBroadcastManager

    By example - Instead of

    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    

    i now use

    sendBroadcast(intent);
    

    instead. This does however mean that the broadcasts are less private.