2

I set some variables to represent the user choosing either using wifi exclusively or with no preference in the Preferences Activity. I then set up a onSharedPreferenceChanged to change the variable based on the user's choice.

The app needs to download data from the internet but I want the user to be able to select some options like Which type of network to use. I was trying to follow the logic of how the activity function and I think the problem is that the variables change in the onSharedPreferenceChanged, but don't get refreshed until I come back, but I am unsure of how to proceed. I found that I can refresh the activity with the Intent Class but it needs to be static within the function but it doesn't work if it's static, so I've coded myself into a corner so to speak.

public class SettingsActivity extends AppCompatActivity {

static final String TAG = "SettingsActivity";
public static final String WIFI = "WiFi";
public static final String FIRST = "First";

public static final String SHARED_PREFS = "sharedPrefs";
public static final String WIFI_CONNECTION = "WiFi";
public static final String CELLULAR_CONNECTION = "Cellular";
public static final String WIFI_PREFERENCE = "WiFi Enabled";
public static final String NO_PREFERENCE = "First Enabled";

public static final String NO_CONNECTION = "No Connection";

public static final String PREF_NETWORK_TYPE = "network_choice";

public static String sPref = null;

private NetworkCheck networkCheck = new NetworkCheck();
SharedPreferences sharedPrefs;
private static boolean prefWifi;
private static boolean noPreferredNetwork;
private static boolean wifiConnected = false;
private static boolean cellularConnected = false;
public static boolean networkConnected;
public static boolean refreshActivity = false;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.settings_activity);
    getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.settings, new SettingsFragment())
            .commit();
    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
        actionBar.setDisplayHomeAsUpEnabled(true);
    }
    PreferenceManager.setDefaultValues(this, R.xml.root_preferences, false);

    IntentFilter filter = new IntentFilter(CONNECTIVITY_SERVICE);
    networkCheck = new NetworkCheck();
    this.registerReceiver(networkCheck, filter);
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (networkCheck != null) {
        this.unregisterReceiver(networkCheck);
    }
}

@Override
public void onStart() {
    super.onStart();
    sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    sPref = sharedPrefs.getString(PREF_NETWORK_TYPE, "First");
    if(sPref == null){
        sPref = FIRST;
    }
    switch (sPref) {
        case WIFI:
            prefWifi = true;
            noPreferredNetwork = false;
            break;
        case FIRST:
            prefWifi = false;
            noPreferredNetwork = true;
            break;
        default:
            prefWifi = false;
            noPreferredNetwork = true;
    }
    Log.i(TAG, "onSharedPreferenceChanged: onStart - " + sPref + " " + prefWifi + " " + noPreferredNetwork);
    Toast.makeText(this, prefWifi + " " + noPreferredNetwork, Toast.LENGTH_LONG).show();

    //checkNetworkFlags(this);
}

@Override
protected void onPause() {
    super.onPause();
    networkType();
    Log.i(TAG, "onSharedPreferenceChanged: onPause- " + sPref + " " + prefWifi + " " + noPreferredNetwork);

}


public void networkType() {
    sharedPrefs = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPrefs.edit();
    editor.putBoolean(WIFI_PREFERENCE, prefWifi);
    editor.putBoolean(NO_PREFERENCE, noPreferredNetwork);
    editor.putBoolean(NO_CONNECTION, networkConnected);
    editor.apply();
}

public static class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey);
    }

    @Override
    public void onResume() {
        super.onResume();
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    }

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

        if (key.equals(PREF_NETWORK_TYPE)) {

            prefWifi = sPref.equals(WIFI);
            noPreferredNetwork = sPref.equals(FIRST);
            if (prefWifi) {
                sPref = WIFI;
                refreshActivity = true;
            } else if (noPreferredNetwork) {
                sPref = FIRST;
                refreshActivity = true;
            }
        }
        Log.i(TAG, "onSharedPreferenceChanged: inTheFragment- " + sPref + " " + prefWifi + " " + noPreferredNetwork);

    }
}

private void refreshActivity(){
    finish();
    startActivity(getIntent());
}
  }

The variables sPref, prefWifi, and noPreferredNetwork don't update until I come back to the activity and I'm not sure where to go with my logic as is written in the code. What am I missing? The refreshActivity at the bottom is not implemented but I thought it would be somewhere to go with it but I just can't think of a way at the moment.

DJ. Aduvanchik
  • 332
  • 5
  • 17

4 Answers4

3

That's because you only update the variables from fragment and didn't update the view in Activity according to the variables value. So, you need to listen for the preference changes in your Activity, then update your view.

Add something like this to your Activity:

SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {

    // update your variables here

    // update your view according to the variables here.

  }
};

sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
  • I used your solution and ended up adding using the refreshActivity within the listener.but the finish() method doesn't destroy the previous instance after I refresh the pages so they end up stacking up. Any idea how to get rid of that? – DJ. Aduvanchik Jul 22 '19 at 18:06
  • 1
    You don't need to recreate the activity, just update the variables value then use the value to change the state of your view. Something like `if(wifiConnected) { hideView();} else { showView(););`. And remove the `static` keyword from your variables. – ישו אוהב אותך Jul 23 '19 at 02:28
  • I thought about that solution but I don't want the settings to close after the choice is made. I'm planning on adding more Settings later. I finally Found the issue. I didn't put ` sPref = sharedPrefs.getString(PREF_NETWORK_TYPE, "First");` into the listener so it was using the old instance of it first. Just wow – DJ. Aduvanchik Jul 23 '19 at 03:33
2

You don't need a static variable - you can read the value directly from SharedPreferences. Also, if you want to communicate from a Fragment to its host Activity, then follow the guidelines in the Android Documentation and do it via an interface.

Or, alternatively, you can register a OnSharedPreferencesChangedListener directly in your Activity (as you do in your SettingsFragment) and respond to any changes there.

PPartisan
  • 8,173
  • 4
  • 29
  • 48
2

This is way more complicated than it would have to be; for example - and the code in onCreate() and onStart() might as well as run in onCreate() - one just has to check for savedInstanceState == null, when inflating the layout. The fragments should handle saving & loading values, because they also know of the UI elements; just imagine more than one such PreferenceFragmentCompat or even better, test it with at least two of them. Get rid of method refreshActivity(), because it seems to be an attempted workaround for a flawed business logic.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
0

The OnSharedPreferenceChangeListener was using the previous instance of the varibalesPref to check against and only updating after I navigated back to the Activity so I added sPref = sharedPrefs.getString(PREF_NETWORK_TYPE, "First"); to the listener inside the if (key.equals(PREF_NETWORK_TYPE)) { so it would check again after the selection was made to then update the other variables.

Edit: Still going to Leave @ישו אוהב אותך 's answer as accepted because calling an instance of the listener is better in this case than implementing it.

DJ. Aduvanchik
  • 332
  • 5
  • 17