3

I am currently trying to develop an app that serves as a shopping list, in which the user enters text into an EditText, presses a Button, which then saves the value into a List, which then updates a ListView with its value. The app works great, except when the user exits the app, in which case all of the values that the user enters are not saved. This is what I have tried so far to store the List.

public class MainActivity extends ListActivity {

    private static final String SHARED_PREFS_NAME = "MY_SHARED_PREF";

    ArrayList<String> mylist = new ArrayList<String>();
    ArrayAdapter<String> adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        ListView listview = (ListView) findViewById(android.R.id.list);

        Button btn = (Button) findViewById(R.id.button);

        mylist = (ArrayList<String>) getArray();

        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mylist);

        OnClickListener listener = new OnClickListener() {          
            @Override
            public void onClick(View v) {                               
                EditText edit = (EditText) findViewById(R.id.edittext);
                mylist.add(edit.getText().toString());
                edit.setText("");               
                adapter.notifyDataSetChanged();
            }
        };

        btn.setOnClickListener(listener);

        listview.setAdapter(adapter);   

    }

    public boolean saveArray() {

        SharedPreferences sp = this.getSharedPreferences(SHARED_PREFS_NAME, Activity.MODE_PRIVATE);
        SharedPreferences.Editor mEdit1 = sp.edit();
        Set<String> set = new HashSet<String>();
        set.addAll(mylist);        
        mEdit1.putStringSet("list", set);

        return mEdit1.commit();     

    }

    public List<String> getArray() {

        SharedPreferences sp = this.getSharedPreferences(SHARED_PREFS_NAME, Activity.MODE_PRIVATE);
        Set<String> set = sp.getStringSet("list", new HashSet<String>());
        return new ArrayList<String>(set);
    }

}

and in my .xml layout file I have

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/edittext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/edittext"
        android:text="Button" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/button" >
    </ListView>

</RelativeLayout>

I have it so that the values can be entered into the ListView correctly, but the ListView does not save its values after the app is exited out of and reopened. Does anyone know why this is occurring?

Etheryte
  • 24,589
  • 11
  • 71
  • 116
  • 3
    You need to read a very basic tutorial on SQLite storage – brandall Jun 01 '14 at 23:24
  • `SharedPreferences` is used to store key-value pairs of primitive data. As @brandall suggests, an SQLite database is preferable when persisting `List` objects. It does not require a lot of code, nor is it difficult to implement. It would make updating, deleting or creating new entries in a shopping list super easy. – Ole Jun 01 '14 at 23:57
  • I tried and reworked your code.. the solution is below, into my response – Massimiliano D'Amico Jun 04 '14 at 17:56

4 Answers4

5

the solution to your problem is as follows:

I tried and reworked your code also thanks to this link:

public class MainActivity extends ListActivity {

    private static final String SHARED_PREFS_NAME = "MY_SHARED_PREF";
    ArrayList<String> mylist = new ArrayList<String>();
    ArrayAdapter<String> adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView listview = (ListView) findViewById(R.id.list);
        Button btn = (Button) findViewById(R.id.button);

        //NOTE: acquire array from shared preferences
        mylist = getArray();

        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mylist);

        OnClickListener listener = new OnClickListener() {          
            @Override
            public void onClick(View v) {                               
                EditText edit = (EditText) findViewById(R.id.edittext);
                mylist.add(edit.getText().toString());
                edit.setText("");               
                adapter.notifyDataSetChanged();
            }
        };
        btn.setOnClickListener(listener);
        listview.setAdapter(adapter);        
    }

    public boolean saveArray() {
        SharedPreferences sp = this.getSharedPreferences(SHARED_PREFS_NAME, Activity.MODE_PRIVATE);
        SharedPreferences.Editor mEdit1 = sp.edit();
        Set<String> set = new HashSet<String>();
        set.addAll(mylist);
        mEdit1.putStringSet("list", set);
        return mEdit1.commit();
    }

    public ArrayList<String> getArray() {
        SharedPreferences sp = this.getSharedPreferences(SHARED_PREFS_NAME, Activity.MODE_PRIVATE);

        //NOTE: if shared preference is null, the method return empty Hashset and not null          
        Set<String> set = sp.getStringSet("list", new HashSet<String>());

        return new ArrayList<String>(set);
    }
}

..and calls SaveArray () before closing the application

public void onStop() {
    saveArray();
    super.onStop();
}

or, alternatively, save the array every time you add an element (all'onclick button overwrites the shared preference in the current list)

Community
  • 1
  • 1
  • when the application starts reload the list from shared preferences? how you do this operation? give me some detail – Massimiliano D'Amico Jun 05 '14 at 07:24
  • myList should be loaded immediately before creating the ArrayAdapter, while SaveArray should be called before end the application. Maybe the problem was that, the first time, the shared preference was empty and then returning a null value .. but now I have slightly modified the code (if you look at the code again.. I commented the updated rows with the prefix NOTE) to permanently solve the problem. – Massimiliano D'Amico Jun 05 '14 at 19:50
  • I tested the application before you write the code, and I assure you that when you restart the app fills the list regularly with the saved values​​. Could you tell me when invoke the method SaveArray() in your code? can you give me some additional info? I've added a button to simulate the data save – Massimiliano D'Amico Jun 05 '14 at 21:43
  • In your code I see that you have implemented the method SaveArray() but I do not see the code that calls the method. one possible solution is to call SaveArray() when the application exits (I updated my answer with the solution) – Massimiliano D'Amico Jun 06 '14 at 07:23
1

Since the listview you are using not custom, i.e. is a android.R.layout.simple_list_item_1.

I recommend saving the items in the listview as a List and then save it to the SharedPreferences. If you only want to save a string in SharedPreferences, following functions will help convert between List and String & vice versa.

private String converttoStringfromList(List<String> list) {
    String convertedString;     
    convertedString = TextUtils.join(",", list);        
    return convertedString;
}



private List<String> converttoListfromString(String serialized) {
    List<String> convertedList = null;      
    convertedList = TextUtils.split(serialized, ",");       
    return convertedList;
}

Updating from discussion in comments: It should also work, more efficiently, to convert between ArrayList<>String, following threads will help how to do this:

Best way to convert an ArrayList to a string

&

How to convert a String into an ArrayList?

Community
  • 1
  • 1
user1406716
  • 9,565
  • 22
  • 96
  • 151
  • Cool, how feasible would it be to convert to a string from an ArrayList instead? I feel like that would take out the middle step of **ArrayList -> ListView -> List -> String**, and make it **ArrayList -> String**. –  Jun 02 '14 at 00:00
  • Yes, that will work and be efficient. These Threads should help to do both: http://stackoverflow.com/questions/599161/best-way-to-convert-an-arraylist-to-a-string & http://stackoverflow.com/questions/7347856/how-to-convert-a-string-into-an-arraylist. I will update my answer too. – user1406716 Jun 02 '14 at 00:11
  • @benzistomejustacar - did the answer help you? Could you please mark one of the three answers as the right answer? – user1406716 Jun 04 '14 at 17:37
  • 1
    Why do you recommend to convert list into a string? What about a case when a string contains `,` - it will cause an extra entry creation while converting. You can just store whole `List` in the `SharedPreferences` as @Massimiliano D'Amico propose. – Pavel Jun 04 '14 at 18:03
0

if the data is not complicate, I will suggest you use shared preference, otherwise, sqlite will be your good option.

shanwu
  • 1,493
  • 6
  • 35
  • 45
0

In your code you miss the logic to save/restore the dataset. Since ArrayList and String are Serializable, you can serialize the List in a file. The logic could be something like:

@Override
public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     mylist = getList(fileName); 
     // other code
}

private void saveList(String fileName, List<String> values) {
 FileOutputStream fos = openFileOutput(fileName, Context.MODE_PRIVATE);
 ObjectOutputStream os = new ObjectOutputStream(fos);
 os.writeObject(values);
 os.close();

}

private List<String> getList(String fileName) {
  FileInputStream fis = context.openFileInput(fileName);
  ObjectInputStream is = new ObjectInputStream(fis);
  List<String> values = (List<String>) is.readObject();
  is.close();
  if (values == null)
       values = new List<String>();
  return values;
}

@Override
protected void onDestroy() {
    super.onDestroy();
    saveList(fileName, values);
}

I wrote it on the fly, you should check for exception, typo, etc..

Blackbelt
  • 156,034
  • 29
  • 297
  • 305