TL;DR
I need to update a fragment's UI(toggleButton) when it is visible on screen from a running Service.
Background
I have a toggleButton
on a Fragment(named homeFragment). It shows Stop text if(toggleButton.isChecked)
, else it shows Start text.
This toggleButton
starts and stops a Service.
Now, there are two ways to stop this service. One is to tap on toggleButton
again(which stops the service) and, the other is through Service itself.
When this service is started, toggleButton
shows 'Stop' text.
This service creates a Sticky Notification and calls this.stopSelf
after that.
This Notification has a button close this notification.
This option calls a BroadcastReceiver
to stop/cancel the notification.
Problem/Requirement
Now, when the service is closed through notification button, If app is visible or in the foreground, I want to trigger that toggleButton
on Fragment to show Start text again.
I don't need to handle this if appActivity is in background/paused/closed (i take care of that through checking sharedPrefs
in onCreate()
)
I tried:
Using a Boolean SharedPref Key(say isServiceRunning
) which keeps track of service state. In onCreate()
, I save a true
boolean. In onDestoy()
, I save a false
boolean.
And then, I register a onSharedPreferencesChangeListener
to sharedPrefs(inside fragment)
which checks if isServiceRunning
's sharedPrefkey is changed or not.
And, if it is, it calls toggleButton.setChecked(false);
This method rarely works. Sometimes it works, sometimes nothing happens.
Using a LocalBroadcastReceiver
, but it has many errors. Like, can't Instantiate Receiver: no empty method
. I tried to resolve,
but figured out that needs a lot of work. And, besides that accessing Fragment views inside another class is just a mess because you have to give them fragment's layout
which can be null
at any time. Giving this receiver class a View
element from onViewCreated()
is difficult. I tried inflating the layout
+ findViewById
to do this,
but no success/error.
This method never worked, i think it is not efficient.
Using static
variables everywhere. So, i made a global View
element(say activeLayout
).
It is private
and static
, so that a static
method(which toggles the state of toggleButton
) can access layout of fragment.
activeLayout
is assigned a Layout from onViewCreated()
method.
Now, if i call this static
method from my stopNotificationReceiver
, it works(i only checked two times). But, a new Warning is shown that:
Warning: Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)
So, i can't make activeLayout
as a static
variable, which breaks this whole idea.
Please suggest me an alternative if i am doing it all wrong. Or correct me on how to do this.
Use a broadcast reciver and register it in your fragment
You can call Broadcast reciver by using below code inside ur service
Intent intent = new Intent();
intent.putExtra("extra", cappello);
intent.setAction("com.my.app");
sendBroadcast(intent);
In your Fragment implement a BroadcastReceiver :
private class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String state = extras.getString("extra");
updateView(state);// update your textView in the main layout
}
}
and register it in onResume() of Fragment:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.my.app");
receiver = new MyBroadcastReceiver();
registerReceiver(receiver, intentFilter);