What I'm trying to do is have a setting menu pull up when a button is pressed on my main menu (settings menu is implemented as a separate activity from my main). For simplicity's sake, assume that my main menu is blank except for 1 button that pulls up the settings menu. In the setting menu, there is one check box and one button "Done" that returns to the main activity.
How do I save a CheckBox's and load it (what should the code be, where should I put it, why, etc) ? I've tried googling it, and trying to replicate the results, but I can't seem to get it. 2 things have happened so far: nothing has saved, or my program crashes.
Once I have the information about the checkbox saved, how am I able to access this information from my main activity #I want to be able to run certain code based on if the user checked the box or not?
some results that I've landed on and tried:
How to save the checkbox state? - android
Saving Checkbox states
(Please keep in mind that I'm completely new to this)
public class Settings extends ActionBarActivity {
private static final String SETTING_CHECK_BOX = "SETTINGS";
private CheckBox cb;
//char boxChecked = '0';
#Override
protected void onCreate(Bundle savedSettings) {
super.onCreate(savedSettings);
cb = (CheckBox) findViewById(R.id.checkBox);
setContentView(R.layout.activity_settings);
cb.setChecked(isCheckedSettingEnabled());
}
private void setCheckedSettingEnabled(boolean enabled) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(SETTING_CHECK_BOX, enabled).apply();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_settings, menu);
return true;
}
private boolean isCheckedSettingEnabled() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean(SETTING_CHECK_BOX, false);
}
public void onPause() {
super.onPause();
// Persist the setting. Could also do this with an OnCheckedChangeListener.
setCheckedSettingEnabled(cb.isChecked());
}
public void clickedDone (View v) {
SharedPreferences settings = getSharedPreferences("SETTINGS", 0);
settings.edit().putBoolean("check",true).commit();
finish();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
So now my app doesn't crash anymore, but the state is not remembered (always unchecked when settings menu is open). I changed cb.setChecked(checkState) to cb.setChecked(TRUE), which didn't change anything (still always unchecked when settings menu is open). What is going on?
onSaveInstanceState() is only for persisting data for that instance of the Activity. Once that Activity has had finish() invoked, that state is no longer relevant. You need to write your settings to persistent storage. A simple storage solution for your case is SharedPreferences.
public class Settings extends ActionBarActivity {
// Create a constant for the setting that you're saving
private static final String SETTING_CHECK_BOX = "checkbox_setting";
private CheckBox mCheckBox;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
mCheckBox = (CheckBox) findViewById(R.id.checkBox);
// Set the initial state of the check box based on saved value
mCheckBox.setChecked(isCheckedSettingEnabled());
}
#Override
public void onPause() {
super.onPause();
// Persist the setting. Could also do this with an OnCheckedChangeListener.
setCheckedSettingEnabled(mCheckBox.isChecked());
}
/**
* Returns true if the setting has been saved as enabled,
* false by default
*/
private boolean isCheckedSettingEnabled() {
return PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(SETTING_CHECK_BOX, false);
}
/**
* Persists the new state of the setting
*
* #param enabled the new state for the setting
*/
private void setCheckedSettingEnabled(boolean enabled) {
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.putBoolean(SETTING_CHECK_BOX, enabled)
.apply();
}
}
Once the state data is stored using onSaveInstanceState(), the system uses onRestoreInstanceState(Bundle savedInstanceState) to recreate the state.
If you are using onSaveInstanceState() You have to override the function onRestoreInstanceState() in the activity or use the saved state in onCreate(). I think it's better to use onRestoreInstanceState() , which can reduce the code in onCreate(), because the onSavedInstanceSate() is called only when the system
closes the app to make room for new applications to run. If you just want to save the checked state , use shared preference, no need of onSaveInstanceState().
//decalre in class
private CheckBox cb;
private SharedPreferences preferences ;
private SharedPreferences.Editor editor;
private boolean CHECKED_STATE;
#Override
protected void onCreate(Bundle savedSettings) {
super.onCreate(savedSettings);
setContentView(R.layout.activity_settings);
preferences = getApplicationContext().getSharedPreferences("PROJECT_NAME", android.content.Context.MODE_PRIVATE);
editor = preferences.edit();
CHECKED_STATE = preferences.getBoolean("check", false);
cb = (CheckBox) findViewById(R.id.checkBox);
cb.setChecked(CHECKED_STATE);
cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
editor.putBoolean("check", isChecked);
editor.commit();
}
});
}
this code saves the state on clicking the check box.
To make it save the state on Back Press , add the following to your activity.
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
editor.putBoolean("check", cb.isChecked());
editor.commit();
}
for more details on Save instance state please refer this link.
Related
I wanted to add a `toast message` when clicked on a button and I added it. Now I want show it only **one time**, that means the toast message will **not show again** if clicked on the button after the first time **also after a restart of app**.
Please help me!
You can do it with SharedPreferences that you store in another class like Utility.java:
public class Utility {
public static SharedPreferences preferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
public static Boolean hasSendToast(Context context) {
return preferences(context).getBoolean("Toast", false);
}
public static void setSendToast(Context context, Boolean bool) {
preferences(context).edit()
.putBoolean("Toast", bool).apply();
}
}
And use it with your Toast inside the onClickListener in your MainActivity.java like this:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(v -> {
if (!Utility.hasSendToast(getApplicationContext())) {
Toast.makeText(getApplicationContext(), "My Toast", Toast.LENGTH_SHORT)
.show();
Utility.setSendToast(getApplicationContext(), true);
}
});
}
}
You might want to look into https://developer.android.com/training/data-storage/shared-preferences. After the first click write a boolean into shared preferences to indicate the first click has happened. Next time the user clicks the button make sure to check if that boolean has been set and don't show the toast if that's the case.
You can use a boolean flag and store the value using Shared Preference.
btn.onClickListener {
if(!getToastShownStatusFromSharedPreference()) {
showToast()
changeToastShowsStatusToSharedPreference()
}
/* other operations */
}
Yes you can do that with SharedPreferences which is a pref manager in android. You can follow the below process:
Declare a boolean as like isFirstTime = true.
On the click of the button check boolean status, and if its true then fire the toast message and make isFirstTime = false.
That's it.
I have the main activity class with a TextView and a settings activity (generated from the Android's Studio template).
On the settings activity, I've declared many settings. The TextView on the main activity shows one of this settings, this is made by a function that loads the current state of all preferences and saves them on variables.
If I change something on the settings activity the listener will execute, but the value won't be updated on the main activity.
I can't use onResume() method because it's also executed the first time the app is launched.
I've tried sending an Intent and starting the main class from the listener, but that creates a new instance of the main class, and only allows you to change just one preference because the listener triggers.
My main activity looks like:
public class MainActivity extends ActionBarActivity {
private SharedPreferences prefs;
private double _lat;
public void loadPrefs(){
prefs = PreferenceManager.getDefaultSharedPreferences(this);
_lat = Double.parseDouble(prefs.getString("lat", ""));
//updates the iu
TextView helloThere = (TextView) findViewById(R.id.TextView_hello_world);
helloThere.setText(Double.toString(_lat));
}
#Override
protected void onResume() {
super.onResume();
String changes = getIntent().getStringExtra("prefChanged");
if(changes != null)
Log.d("DEBUG!!!!", changes);
else
Log.d("DEBUG!!!!", "No changes!!!!");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadPrefs();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (id == R.id.action_settings) {
// Launch Settings activity
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
}
And this is the settings activity (look the function called onSharedPreferenceChanged):
public class SettingsActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
SharedPreferences.OnSharedPreferenceChangeListener listener;
/**
* Determines whether to always show the simplified settings UI, where
* settings are presented in a single list. When false, settings are shown
* as a master/detail two-pane view on tablets. When true, a single pane is
* shown on tablets.
*/
private static final boolean ALWAYS_SIMPLE_PREFS = false;
private SharedPreferences prefs;
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d("DEBUG!!","LISTENER!!");
Intent i = new Intent(this, MainActivity.class);
i.putExtra("prefChanged","Something changed...");
startActivity(i);
}
#Override
protected void onResume() {
super.onResume();
prefs.registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onPause() {
super.onPause();
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setupSimplePreferencesScreen();
}
/**
* Shows the simplified settings UI if the device configuration if the
* device configuration dictates that a simplified, single-pane UI should be
* shown.
*/
private void setupSimplePreferencesScreen() {
if (!isSimplePreferences(this)) {
return;
}
// In the simplified UI, fragments are not used at all and we instead
// use the older PreferenceActivity APIs.
// Add 'general' preferences.
addPreferencesFromResource(R.xml.pref_general);
// Add 'notifications' preferences, and a corresponding header.
PreferenceCategory fakeHeader = new PreferenceCategory(this);
fakeHeader.setTitle(R.string.pref_header_notifications);
getPreferenceScreen().addPreference(fakeHeader);
addPreferencesFromResource(R.xml.pref_notification);
// Add 'data and sync' preferences, and a corresponding header.
//fakeHeader = new PreferenceCategory(this);
//fakeHeader.setTitle(R.string.pref_header_data_sync);
//getPreferenceScreen().addPreference(fakeHeader);
//addPreferencesFromResource(R.xml.pref_data_sync);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences to
// their values. When their values change, their summaries are updated
// to reflect the new value, per the Android Design guidelines.
//bindPreferenceSummaryToValue(findPreference("example_text"));
//bindPreferenceSummaryToValue(findPreference("example_list"));
bindPreferenceSummaryToValue(findPreference("notifications_ringtone"));
//bindPreferenceSummaryToValue(findPreference("sync_frequency"));
}
/**
* {#inheritDoc}
*/
#Override
public boolean onIsMultiPane() {
return isXLargeTablet(this) && !isSimplePreferences(this);
}
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* Determines whether the simplified settings UI should be shown. This is
* true if this is forced via {#link #ALWAYS_SIMPLE_PREFS}, or the device
* doesn't have newer APIs like {#link PreferenceFragment}, or the device
* doesn't have an extra-large screen. In these cases, a single-pane
* "simplified" settings UI should be shown.
*/
private static boolean isSimplePreferences(Context context) {
return ALWAYS_SIMPLE_PREFS
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
|| !isXLargeTablet(context);
}
/**
* {#inheritDoc}
*/
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
if (!isSimplePreferences(this)) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* #see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
//bindPreferenceSummaryToValue(findPreference("fixed_lat_long"));
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_ringtone"));
}
}
}
Bonus question: I've generated the settings activity using the Android's Studio template, I've noticed that there's no onCreate() method, is this normal? What does executed when I call the startactivity() function from the main activity?
Thank you.
PS: Maybe I've posted too many code to solve the question, sorry I just started with Android and feel like a noob.
You should not trying to change the UI of MainActivity from SettingsActivity ! The management of the MainActivity's UI should only be done by itself.
Take a look at the Activity Lifecycle. You will see that the onResume() method of the MainActivity will be called when the Activity will come back on the foreground. So two solutions :
You call loadPrefs() in the onResume(). You tell you can't do it, but I don't understand why (maybe I miss some details)
In the onResume() method, call loadPrefs() only if changes are detected.
Again : do not try to call a method of MainActivity from another class : it's a non-sense in Android world.
Bonus anwser
The onCreate() method is declared in the Activity class and so has a default behavior. If you want to modify the default behavior (i.e. declaring your own UI components), you can override it (doing so when adding #Override annotation). So by default, there is no absolut need to override it. And if not override the default implementation will be called. It's an OOP basis ;)
No need to start main activity from settings activity
Call loadPrefs() from main activity's onResume() rather than from onCreate()
There is onCreate() method in settings activity.
My MainActivity calls an AsyncTask to do some network I/O. When the AsyncTask begins, I would like to 'light up' an icon in the ActionBar. When the AsyncTask completes, I would like to make that ActionBar icon invisible, i.e. upon AsyncTask completion, not via a button click.
At this point I can successfully light up the ActionBar icon upon AsyncTask start. At the completion of AsyncTask, I send another broadcast back to MainActivity to indicate that AsyncTask is completed. I need to be able to use this broadcast to make the ActionBar icon invisible. I am attempting to used InvalidateMenuOptions() to force onPrepareMenuOptions to recreate and make the ActionBar icon invisible, but it is not working. Here is my attempt so far - all code is excerpted from my MainActivity class
excerpt from MainActivity:
public class MainActivity extends Activity {
private static boolean dataXferRunning = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ActionBar actionBar = getActionBar();
actionBar.setHomeButtonEnabled(true);
// broadcast receiver to determine if BasestationTransfer is active
basestationBroadcastReceiver = new BasestationBroadcastReceiver();
basestationIntentFilter = new IntentFilter("XFER_RUNNING_ACTION");
boolean hasWifi = CWICUtil.getNetworkState(this);
if(hasWifi) {
if(dataXferRunning == false) {
containerCount = 0;
DBAdapter dbAdapter = CWICApplication.dbAdapter();
try {
containerCount = (int)dbAdapter.getUnsentContainersCount();
} catch (SQLException e) {
Log.e(TAG, "getUnsentContainersCount() failed: " + e.toString());
e.printStackTrace();
}
if(containerCount > 0) {
invalidateOptionsMenu();
startTransfer(); //AsyncTask
invalidateOptionsMenu();
}
}
}
}
}
my BroadcastReciever:
public static class BasestationBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent.getAction();
boolean isRunning = intent.getBooleanExtra("XFER_RUNNING", false);
if(isRunning) {
dataXferRunning = true;
} else {
dataXferRunning = false;
}
}
};
my onPrepareOptionsMenu:
#Override
public boolean onPrepareMenuOptions(Menu menu) {
if(dataXferRunning) {
menu.findItem(R.id.action_socketServiceConnected).setVisible(true);
} else {
menu.findItem(R.id.action_socketServiceConnected).setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
}
So to summarize - I'm successfully receiving broadcasts from my AsyncTask with correct values. I have seen much code that does this with a buttonClick, however my issue is dynamically making my ActionBar icon invisible upon completion of AsyncTask. Also - this is my first time posting, let me know if I can clarify any issues plus thanks to this community because you have been getting me out of jams for months now.
In onCreateOptionsMenu(), you can hold on to a reference of your Menu object (via a class variable, or some other mechanism of your choice), like this:
Menu menu;
#Override
public boolean onCreateOptionsMenu( Menu menu ) {
getSupportMenuInflater().inflate( R.menu.my_menu, menu );
this.menu = menu;
return true;
}
Then, when you want to dynamically adjust the menu item's visibility, you can reuse that menu object reference to call menu.findItem(R.id.myId) to get your individual menu items and adjust their properties dynamically however you'd like.
I need to stored my listview that i create dynamically by a "add" button. Of course right now if i go out of application the items disappears. I tryied in this way but something's wrong
public class MainActivity extends Activity{
private EditText etInput;
private Button btnAdd;
private ListView lvItem;
private ArrayList<String> itemArrey;
private ArrayAdapter<String> itemAdapter;
/* Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setUpView();
// Eliminare un elemento al longClick con dialog di conferma
lvItem.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View v,
final int position, long id) {
// TODO Auto-generated method stub
AlertDialog.Builder adb = new AlertDialog.Builder(
MainActivity.this);
adb.setTitle("Are you sure");
adb.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
itemArrey.remove(position);
itemAdapter.notifyDataSetChanged();
}
});
adb.setNegativeButton("No",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
adb.show();
return false;
}
});
lvItem.setClickable(true);
lvItem.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Object o = lvItem.getItemAtPosition(position);
Intent intent2 = new Intent(getApplicationContext(), MainActivity.class); // Mettere settings.class quando creata
MainActivity.this.startActivity(intent2);
}
});
}
private void setUpView() {
etInput = (EditText)this.findViewById(R.id.editText_input);
btnAdd = (Button)this.findViewById(R.id.button_add);
lvItem = (ListView)this.findViewById(R.id.listView_items);
itemArrey = new ArrayList<String>();
itemArrey.clear();
itemAdapter = new ArrayAdapter<String>(this, R.layout.customlistview,itemArrey);
lvItem.setAdapter(itemAdapter);
btnAdd.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
addItemList();
}
});
}
protected void addItemList() {
if (isInputValid(etInput)) {
itemArrey.add(0,etInput.getText().toString());
etInput.setText("");
itemAdapter.notifyDataSetChanged();
}
}
protected boolean isInputValid(EditText etInput2) {
// TODO Auto-generatd method stub
if (etInput2.getText().toString().trim().length()<1) {
etInput2.setError("Insert value");
return false;
} else {
return true;
}
}
// Shared preferences
protected void SavePreferences(String key, String value) {
// TODO Auto-generated method stub
SharedPreferences data = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = data.edit();
editor.putString(key, value);
editor.commit();
}
protected void LoadPreferences(){
SharedPreferences data = PreferenceManager.getDefaultSharedPreferences(this);
String dataSet = data.getString("LISTS", "None Available");
itemAdapter.add(dataSet);
itemAdapter.notifyDataSetChanged();
}
I don't know how "call" the shared preferences and i don't know if in this way it's correct. Right now nothing happen, nothing is saving. Someone can help me please? Thanks
You should look at this API training about activity life cycle:
http://developer.android.com/training/basics/activity-lifecycle/index.html
and also this:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
As you can see, your activity can be gone because the user actively destroy it (using the back button) or the system can destroy it. If they system destroy it you can use onSaveInstanceState to save the data and onCreate to retrieve it. In that case you do not have to use SharedPreferences - just use Bundle as described in the link.
However, if you want to persist your data when the user close it, you should save your data when the call back onDestroy() is called. And retrieve the data when onCreate() is called. onDestroy() is called before the system thinks that your activity is not needed anymore, like when the user click the "back" button. In that case you do have to use one of the storage method provided by android, including Shared preferences. Like someone else said, it requires a "key, value" mechanism, so it might not match 100% with what you do. Using sqlLite is a bit heavy weight for this task, since your data is not really of a table type either (a single column table, actually, which is still not database worthy IMO). I think the best way to store your list is to use internal file. When onDestroy() is called, grab all your data and save to a file. When onCreate() is called, read the file and repopulate your list. You can read about android file system, including internal files here:
http://developer.android.com/training/basics/data-storage/files.html
As a close note, if the user press the "Home" button, your activity will not be destroyed. If he then "Force close" your app then nothing will be saved. If you still want to save it even in that case, I suggest you to save your data when "onStop()" is called and reset your list when onStart() is called.
Right now nothing happen, nothing is saving.
That's because you never call your SavePreferences() method.
If you want to continue using SharedPreferences to store the data in your list, you will need to call SavePreferences() on every item in the list.
However, SharedPreferences are used for storing data in a key-value format. This means that every item in your list will require a key, and you need to know that key to retrieve the data. If your list can contain a variable number of items, SharedPreferences is likely not what you want.
I recommend reading the Storage Options documentation, which provides a complete example using Shared Preferences correctly, and discusses other options which may better suit your needs.
I can't figure out how I would go about implementing an up button in a PreferenceScreen. An up button displays a caret in your action bar next to your app icon that allows you to navigate the app's hierarchy, more info here.
I have a Preference Fragment that displays when my main activity is opened and I can get the up button to display by adding this line " getActionBar().setDisplayHomeAsUpEnabled(true);":
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
This causes the up button to display in the Preference Fragment, but I only want to show the up button when one of my PreferenceScreens is opened, allowing navigation to the main PreferenceFragment.
My app is analogous to the main settings app. Only the child screens, like Location Access, that opens from the main Settings app has the up arrow.
From this question, I simply added these two code blocks to my Preference Fragment:
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
// If the user has clicked on a preference screen, set up the action bar
if (preference instanceof PreferenceScreen) {
initializeActionBar((PreferenceScreen) preference);
}
return false;
}
And this one:
/** Sets up the action bar for an {#link PreferenceScreen} */
public static void initializeActionBar(PreferenceScreen preferenceScreen) {
final Dialog dialog = preferenceScreen.getDialog();
if (dialog != null) {
// Inialize the action bar
dialog.getActionBar().setDisplayHomeAsUpEnabled(true);
// Apply custom home button area click listener to close the PreferenceScreen because PreferenceScreens are dialogs which swallow
// events instead of passing to the activity
// Related Issue: https://code.google.com/p/android/issues/detail?id=4611
View homeBtn = dialog.findViewById(android.R.id.home);
if (homeBtn != null) {
OnClickListener dismissDialogClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
};
// Prepare yourselves for some hacky programming
ViewParent homeBtnContainer = homeBtn.getParent();
// The home button is an ImageView inside a FrameLayout
if (homeBtnContainer instanceof FrameLayout) {
ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent();
if (containerParent instanceof LinearLayout) {
// This view also contains the title text, set the whole view as clickable
((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener);
} else {
// Just set it on the home button
((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener);
}
} else {
// The 'If all else fails' default case
homeBtn.setOnClickListener(dismissDialogClickListener);
}
}
}
}
If your complete application is a preferences screen, then you can make your main activity a PreferenceActivity and the sub-levels can be fragments. This way the 'up' functionality is going to be by default what you are looking for.
Have a look at this.
For the XML:
<Preference android:title="Acts like a button"
android:key="button"
android:summary="This will act like a button"/>
Then for the Java in your onCreate()
Preference button = (Preference)findPreference("button");
button.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
//code for what you want it to do
return true;
}
});