Gastón Saillén
Gastón Saillén

Reputation: 13159

How to handle a Remote Config instance inside a singleton

What I'm trying to do is to make a singleton of a Remote Config fetch in order to load it at first time in my SplashScreen.

While my splashscreen is loading I fetch the data with my remote config singleton once, and then, I just access the value inside each class that I need the value of that Remote Config

I'm doing this to prevent the users to see the changes while they are on the Activity, this is due a christmas theme that I'm making in order to show a custom layout with Remote config

All is working fine (sometimes) and the theme is changing all over the app with this singleton, but there are sometimes that the asynchronous fetch time that must take returns after my SplashScreen is loaded, so I can see the theme changed in the rest of my Activities but not in the main one after the SplashScreen

This is my singleton

public class PruebaSingleton {

    private boolean christmasEvent;
    private FirebaseRemoteConfig mFirebaseRemoteConfig;
    private static volatile PruebaSingleton _instance;

 private PruebaSingleton(){
        fetchRemoteConfig();
    }

    public synchronized static PruebaSingleton getInstance(){
        if(_instance == null){

            synchronized (PruebaSingleton.class) {
                if (_instance == null) _instance = new PruebaSingleton();
            }
        }

        return  _instance;
    }

    private void fetchRemoteConfig() {
        mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
        mFirebaseRemoteConfig.setConfigSettings(
                new FirebaseRemoteConfigSettings.Builder().setDeveloperModeEnabled(BuildConfig.DEBUG)
                        .build());

        mFirebaseRemoteConfig.fetch(0).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {

                 mFirebaseRemoteConfig.activateFetched();

            }

            christmasEvent = mFirebaseRemoteConfig.getBoolean("christmas_ottaa_mode");

        }).addOnFailureListener(e -> {

        });
    }
    public boolean isChristmasModeEnabled(){
        return christmasEvent;
    }

Now, after this, I just instantiate once this singleton to fetch the data of the remote config and impact my whole app.

At my SplashScreen onCreate()

PruebaSingleton.getInstance();

And then I just get the boolean value in all my Activities this way

PruebaSingleton.getInstance().isChristmasModeEnabled();

And then with that, I can change the theme.

The thing is that sometimes (not usually but it happened like 2 times in about 10 launches) the fetch from the singleton inside my SplashScreen gets the data after the splash screen sends to the first Activity, this causes my first Activity to not showup the theme but my others Activities does.

My question is

Is there anyway to handle the fetch while I'm in my SplashScreen ?

Thinking on making an interface will slowdown my SplashScreen a little bit untill all the fetch work is done at the singleton class, but also I dont want to show any popup dialog at the first Activity to tell users that is waiting for a fetch.

This is more of a performance issue because while the fetch is done, the splashscreen needs to go fast to the first activity and not wait more time to get the data, because if that happens I will reduce performance on the app trying to load a christmas theme.

Also the first fetch should work properly, the second launch will load the data that was fetched at first time and then wait for 12hs to request the new data, so I need to have all the Activities with the fetch value in true at the first time.

Upvotes: 0

Views: 1240

Answers (2)

Gastón Saillén
Gastón Saillén

Reputation: 13159

I have solved the issue with a simple callback as Doug says, here is what I have made and how it works.

First I created an Interface that will call when the value true or either false of the fetch is done:

public interface SingletonListener {

    void onRemoteFetch(boolean isFetched);
}

Then in my singleton I just fill the value of the interface when I know it's fetched, if an error occurs I just set it to false:

 mFirebaseRemoteConfig.fetch(0).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {

                mFirebaseRemoteConfig.activateFetched();

            }

            christmasEvent = mFirebaseRemoteConfig.getBoolean("christmas_ottaa_mode");
            mSingletonListener.onRemoteFetch(christmasEvent);
        }).addOnFailureListener(e -> {

            mSingletonListener.onRemoteFetch(false);

        });



   //Setters and getters, so in Splash, when I know it's fetched I just set the value to the Singleton and then just get it everywhere in the app
   
 public boolean isChristmasMode() {
            return christmasMode;
        }
    
        public void setChristmasMode(boolean christmasMode) {
            this.christmasMode = christmasMode;
        }

and the set of the implementation of this interface:

public void setInterfaz(SingletonListener listener){
        this.mSingletonListener = listener;
    }

Then in my SplashScreen I just wait until that value is fetched to go to the dashboard, since it's a loading screen I'm not really caring about waiting 1 or 2 more seconds:

Init the singleton and attach the interface

RemoteConfigSingleton.getInstance().setInterfaz(this);

and then implement the method and wait for the result to access the dashboard:

 @Override
    public void onRemoteFetch(boolean isFetched) {
        accessDashboard();
        RemoteConfigSingleton.getInstance().setChristmasMode(isFetched);
    }

Since I don't care about the value of the fetch, either is true or false, I access to the dashboard just after I know that the data has been fetched, if it is fulfilled or an error has occurred.

Then for example in any Activity that I need to change the theme of something I just call the boolean value returned by the christmasEvent, now that I know that it has some value:

        if(RemoteConfigSingleton.getInstance().isChristmasMode()){
            toolbar.setBackgroundResource(R.color.christmas);
            Christmas stuff...
        }
    }

Upvotes: 1

Doug Stevenson
Doug Stevenson

Reputation: 317828

Your singleton needs to expose a way to let some other code attach a listener to know when the fetch is complete, similar to the way you're attaching a listener to the Task that performs a fetch. Or you can just expose the Task itself.

The Task I'm referring to is returned by this:

mFirebaseRemoteConfig.fetch(0)

Upvotes: 1

Related Questions