简体   繁体   中英

Update Fragment UI from Service or BroadcastReceiver if Fragment is visible

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:

  1. 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.

  2. 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.

  3. 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); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM