My App has a Toolbar serving as an action bar with a menu inflated in onCreateOptionsMenu(). One of those menu items shows the state of a service we use. I can change the text and color of that view without issue, but I cannot reliably set the the initial state, because when I try to set the initial state, findViewById(R.id.menu_listening_item) returns null.
Here is my code that sets the view's state:
final TextView statusView = findViewById(R.id.menu_item);
if(statusView == null) {
initialMode = newMode;
return;
}
switch(newMode) {
case SpeechDetector.FIRST_MODE:
statusView.post(() -> {
statusView.setText(R.string.first_mode);
statusView.setTextColor(Color.WHITE);
statusView.setBackgroundColor(Color.BLUE);
});
break;
....
Since this is called by service code initially, I'm storing the value if the view is null. Then I'll call this code again when the view is not null, but how?
I've tried calling it again in onResume(), onCreateOptionsMenu() and onPrepareOptionsMenu(), but none of those are called when the view exists. I'd like to avoid spin loops for obvious reasons.
When is the right time to run after the view exists?
Since Android doesn't have any good ways to do this that I could find, I worked around it by creating a custom button/view. That view, when created subscribes to the service and then when deleted, unsubscribes.
In my menu.xml:
<item
android:id="@+id/menu_custom_item"
app:showAsAction="always|withText"
android:title="@string/custom"
app:actionLayout="@layout/custom_button">
</item>
This is pulled in by my toolbar for the menu. The custom_button layout is:
<com.company.package.views.CustomButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
The constructor for the CustomButton then subscribes to the service, which will tell it when to update. Lastly (and tricky to find), I needed to unsubscribe when the CustomButton goes away:
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Don't leak memory, unsubscribe from the Service here
}
I've left out a few steps of creating a custom view object, but those are easily found and everyone's circumstances are a little different. I hope this helps someone else.