I am creating a To Do List. Right now my app adds and removes data to and from a ListView. However, when I close my application the data gets erased. I want to use SharedPreferences to save the data onDestroy(), then when my app opens I wanted the data to reload.
However, I don't know how to go about accomplishing this task. Can anybody help me with saving a ListView using Shared Preferences (aka I am looking for code)?
There are tutorials for just one shared preference I am looking to dynamically add multiple strings when my application closes. Then when I reopen it, the data will appear. I am only using ONE ACTIVITY page, everything will occur on one page.
HERE IS MY CODE:
public class Main_ToDoList extends Activity implements OnClickListener
{
private Button btnAdd;
private EditText et;
private ListView lv;
ArrayList<String> list = new ArrayList<String>();
ArrayAdapter<String> adapter;
final Context context = this;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
btnAdd = (Button)findViewById(R.id.addTaskBtn);
btnAdd.setOnClickListener(this);
et = (EditText)findViewById(R.id.editText);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, list);
// set the lv variable to your list in the xml
lv=(ListView)findViewById(R.id.list);
lv.setAdapter(adapter);
// set ListView item listener
lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setTitle("Confirm Delete");
alertDialogBuilder.setMessage("Sure you want to delete?");
alertDialogBuilder.setCancelable(false);
alertDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialogInterface, int i)
{
adapter.remove(adapter.getItem(position));
}
});
alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialogInterface, int i)
{
dialogInterface.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
});
}
public void onClick(View v)
{
String input = et.getText().toString();
if(input.length() > 0)
{
adapter.add(input);
et.setText("");
}
}
@Override
public void onDestroy()
{
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main__to_do_list, menu);
return true;
}
}
Android SharedPreferences is used to store a single key-value paired data. In other words, it is not made to store repetitive and complex data. In your case, a list view may contain than 100 rows or more depends on your app. If you were to create a SharedPreferences object for each row it would be 100+ of it, which is not efficient at all. The solution for this is as suggested above, is to use the Android's SQLite database.
A good tutorial: http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
As suggested by Stefano Munarini, you can use a database.
On the other hand, you can loop on the elements of your ArrayAdapter (wrapping your ArrayList) and store them to your SharedPreferences as in:
public static final String PREFERENCES_TODO = "TODO_List_Shared_Preferences";
// ...
SharedPreferences prefs = context.getSharedPreferences(PREFERENCES_TODO,
MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
// This will remove all entries of the specific SharedPreferences
editor.clear();
for (int i = 0; i < adapter.getCount(); ++i){
// This assumes you only have the list items in the SharedPreferences.
editor.putString(String.valueOf(i), adapter.getItem(i));
}
editor.commit();
// ...
// And the reverse process:
SharedPreferences prefs = context.getSharedPreferences(PREFERENCES_TODO,
MODE_PRIVATE);
for (int i = 0;; ++i){
final String str = prefs.getString(Integer.valueOf(i), "");
if (!str.equals("")){
adapter.add(str);
} else {
break; // Empty String means the default value was returned.
}
}
Some considerations:
- Save SharedPreferences in onPause() rather than in onDestroy() which is not guaranteed to be called. See Activity Lifecycle for reference.
- Forbid user from inputing an empty String. (Edit: You are already doing that.)
- If you know there won't be 2 identical String (forbidden or otherwise), you can use the
SharedPreferences.Editor.putStringSet(String, Set<String>)
to use a single entry.
- If there is a lot of elements or if you're planning on adding extra options (i.e. Due date, Category, etc.) You should really consider the database options since the SharedPreferences solution doesn't provide good scalability.
I know its old but i want to share my solution for those who Still want to use sharepref and see this post.
1) create custom class that extends ArrayAdapter and override the toString method.just append and put ',' between every line.
public class GroceryArrayAdapter extends ArrayAdapter<String> {
public GroceryArrayAdapter(Context context, int resource) {
super(context, resource);
}
public GroceryArrayAdapter(Context context, int resource, int textViewResourceId) {
super(context, resource, textViewResourceId);
}
public GroceryArrayAdapter(Context context, int resource, int textViewResourceId, String[] objects) {
super(context, resource, textViewResourceId, objects);
}
public GroceryArrayAdapter(Context context, int resource, String[] objects) {
super(context, resource, objects);
}
public GroceryArrayAdapter(Context context, int resource, List<String> objects) {
super(context, resource, objects);
}
public GroceryArrayAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}
@Override
public String toString(){
String data = "";
for (int i = 0; i < getCount(); i++) {
data += getItem(i).toString() ;
if( i + 1 < getCount()){
data += ",";
}
}
return data;
}
}
2)Save the data as one string. put it in onPause()
private void saveData(){
sharedPrefs = activity.getSharedPreferences(Constants.APPSharePref,
Context.MODE_PRIVATE);
SharedPreferences.Editor e = sharedPrefs.edit();
e.putString(Constants.GROCERY,**grocery_adapter.toString()**);
e.commit();
}
3)In onResume restore the data back by splinting the string with ',' and add it to the adapter.
private void loadDataFromPref(){
sharedPrefs = getActivity().getSharedPreferences(Constants.APPSharePref,
Context.MODE_PRIVATE);
String gList =sharedPrefs.getString(Constants.GROCERY,"");
if(!"".equals(gList) && ""!=gList){
String [] str = gList.split(",");
for (String item : str) {
grocery_adapter.add(item);
}
}
}