Android Broadcast Receiver SharedPreferences empty on initial Activity's onResume

848 views Asked by At

Here's my onResume call in the MainActivity:

@Override
public void onResume() {
    super.onResume();

    SharedPreferences settings = context.getSharedPreferences(INSTALL_PREFERENCE, 0);
    String referrerString = settings.getString(REFERRAL_KEY, null);
    Map<String, String> params = new HashMap<~>();
    if (referrerString != null){
         params.put("referrer", referrerString);
    }
}

Here's my onResume in the class that extends BroadcastReceiver:

@Override
    public void onReceive(Context context, Intent intent){
        try{
            String referrerString = intent.getStringExtra("referrer");

            if(null != referrerString){
                String referrer = URLEncoder.encode(referrerString, "UTF-8");
                context.getSharedPreferences(INSTALL_PREFERENCE, Context.MODE_PRIVATE).edit().putString(REFERRAL_KEY, referrer).commit();
            }

        }
        catch (Exception e){
            //don't handle exceptions for now
        }
    }

The issue is that when I call the MainActivity by opening the app, my app will not return the referrer on the first open. Is there a reason the SharedPreferences will not store my referrer on the first application open? I want to pass back the referrer on the first open and not the second.

3

There are 3 answers

5
siva On

on resume() will be executed before the broadcast receiver and hence for the first time you might be receiving null or default value for the referrer and at later pont of time if you reopen the activity you might be getting correct value because onReceive() would have executed by this time.

If your application has any settings preference screen which actually initialises the settings only after opening it so you may have to initialises all the preferences with default values before using it. It could be the reason that sometimes if you open the application you are getting correct values because you might have opened the setting screen.

4
Daniel Nugent On

Here is one way you could fix it. Make your Activity implement the OnSharedPreferenceChangeListener interface, which will call the onSharedPreferenceChanged() callback when any value in the SharedPreference file registered changes.

If the timing is right and you get a value in onResume(), just carry on as you do in your current code.

If you don't have a value yet, then show a ProgressDialog, and wait for the BroadcastReceiver to populate the value. Once the value is modified by the BroadcastReceiver, capture the value in onSharedPreferenceChanged(), and then use it as needed.

Here is the general structure of the solution:

public class MainActivity extends Activity
        implements SharedPreferences.OnSharedPreferenceChangeListener {

    SharedPreferences settings;
    ProgressDialog dialog;
    Map<String, String> params;
    String INSTALL_PREFERENCE = "installpref";
    String REFERRAL_KEY = "referral";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dialog = new ProgressDialog(this);
        params = new HashMap<String, String>();

        settings = this.getSharedPreferences(INSTALL_PREFERENCE, 0);

        settings.registerOnSharedPreferenceChangeListener(this); //added
    }

    @Override
    public void onResume() {
        super.onResume();

        String referrerString = settings.getString(REFERRAL_KEY, null);
        if (referrerString != null){
            params.put("referrer", referrerString);
            //call whatever methods need params to have a value
            //.......
        }
        else{
            //Show progress dialog and wait for BroadcastReceiver to populate referrer
            dialog.setMessage("loading");
            dialog.show();
        }
    }


    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPrefs, String key) {

        if (key.equals(REFERRAL_KEY)){

            //dismiss dialog if it's showing
            if (dialog.isShowing()){
                dialog.dismiss();
            }

            String referrerString = sharedPrefs.getString(REFERRAL_KEY, null);
            if (referrerString != null){
                params.put("referrer", referrerString);
                //call whatever methods need params to have a value
                //.......
            }
        }
    }
}
0
Simon Marquis On

The referrer broadcast is sent slightly after the main component of your app is started. Therefore, you must notify your activity once the broadcast is received.
One simple solution would be to use LocalBroadcastManager between the Receiver and the Activity:

/* BroadcastReceiver */

@Override
public void onReceive(Context context, Intent intent) {
    Bundle extras = intent.getExtras();
    String referrer = (String) extras.get(KEY_REFERRER);
    // save String to SharedPrefrences
    Intent intent = new Intent(ACTION_UPDATE);
    intent.putExtra(KEY_REFERRER, referrer);
    LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}

/*****/

/* Activity*/

private final BroadcastReceiver mUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String referrer = intent.getStringExtra(KEY_REFERRER);
    }
};

@Override
protected void onPause() {
   LocalBroadcastManager.getInstance(this).unregisterReceiver(mUpdateReceiver);
    super.onPause();
}

@Override
protected void onResume() {
    LocalBroadcastManager.getInstance(this).registerReceiver(mUpdateReceiver, new IntentFilter(ReferrerReceiver.ACTION_UPDATE));
    super.onResume();
}

If you need a fully fonctional sample code/app, check out my OpenSource project on GitHub.