Android - Saving and Retrieving List of Customizing Objects using SharedPreferences

    Android provides many ways of storing data of an application. One of this way is called storing data in SharedPreferences. It allows you to save and retrieve data in the form of [key,value] pair, Data saved in SharedPreferences only lost when you clear data or uninstalling the application.
    From API 11, the SharedPreferences.Editor accept sets of strings. You could convert your List into a HashSet or something similar and store it like that. Unfortunately, it doesn't accept saving any other types. Therefore, if you want to save a list of customizing objects (not list of strings), you must convert your customize list to string.
    There is a library called Gson, it is a Java serialization/deserialization library that can convert Java Objects into JSON and back.

    In this post, I'll use Gson to do this requirement. Hope this help you!

1. Start project and import library

- Launch Android Studio and start a new project.
- Download lastest Gson library at Maven Center.
- Import downloaded jar file to your project.
(See this post for more details of importing library process ).
- Project description: user input player name and a score (number) each time and save. After that, retrieve list of scores from SharedPreferences.

2. Making layouts for application

- Activity layout:
activity_main.xml
<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">

    <LinearLayout
        android:id="@+id/layout_add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_add"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/add" />

        <Button
            android:id="@+id/btn_get"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/get" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/layout_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/layout_add"
        android:layout_margin="10dp"
        android:orientation="vertical"
        android:visibility="gone">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="1"
                android:text="@string/name"
                android:textColor="@android:color/holo_blue_dark" />

            <EditText
                android:id="@+id/txt_name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:inputType="textPersonName" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="1"
                android:text="@string/score"
                android:textColor="@android:color/holo_blue_dark" />

            <EditText
                android:id="@+id/txt_score"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:inputType="number" />
        </LinearLayout>

        <LinearLayout

            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_ok"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="@string/ok" />

            <Button
                android:id="@+id/btn_cancel"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="@string/cancel" />
        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/layout_listview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/layout_add"
        android:visibility="gone"
        android:layout_marginTop="5dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_blue_light"
            android:padding="10dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/list_header"
                android:textColor="@android:color/white" />
        </LinearLayout>

        <ListView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            ></ListView>
    </LinearLayout>
</RelativeLayout>
- Each ListView row layout:
item_listview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textColor="@android:color/holo_green_dark" />

    <TextView
        android:id="@+id/score"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textColor="@android:color/holo_orange_dark" />

</LinearLayout>

3. Programmatically coding

    Create a model object (for saving user score):
HighScore.java
package info.devexchanges.storelistofobjectsbygson;

public class HighScore {

    private String score;
    private String playerName;

    public String getPlayerName() {
        return playerName;
    }

    public void setPlayerName(String playerName) {
        this.playerName = playerName;
    }

    public String getScore() {
        return score;
    }

    public void setScore(String score) {
        this.score = score;
    }
}
    Create a "customizing" SharedPreferences class like this:
MySharedPreference.java
package info.devexchanges.storelistofobjectsbygson;

import android.content.Context;
import android.content.SharedPreferences;

public class MySharedPreference {
    private SharedPreferences pref;
    private SharedPreferences.Editor editor;
    // Context
    private Context _context;

    // Shared pref mode
    int PRIVATE_MODE = 0;

    // Sharedpref file name
    private static final String PREF_NAME = "pref";
    private static final String SCORES = "scores";

    public MySharedPreference(Context context) {
        this._context = context;
        pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
        editor = pref.edit();
    }

    public void saveHighScoreList(String scoreString) {
        editor.putString(SCORES, scoreString);
        editor.commit();
    }

    public String getHighScoreList() {
        return pref.getString(SCORES, "");
    }
}
    In our activity, two most important methods is saving and retrieving list of scores from SharedPreferences:
    /**
     * Save list of scores to own sharedpref
     * @param scoresList
     */
    private void saveScoreListToSharedpreference(ArrayList scoresList) {
        //convert ArrayList object to String by Gson
        String jsonScore = gson.toJson(scoresList);

        //save to shared preference
        sharedPreference.saveHighScoreList(jsonScore);
    }

    /**
     * Retrieving data from sharepref
     */
    private void getHighScoreListFromSharedPreference() {
        //retrieve data from shared preference
        String jsonScore = sharedPreference.getHighScoreList();
        Type type = new TypeToken>(){}.getType();
        scores = gson.fromJson(jsonScore, type);

        if (scores == null) {
            scores = new ArrayList<>();
        }
    }
    Full code of main activity:
MainActivity.java
package info.devexchanges.storelistofobjectsbygson;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private View btnAdd;
    private View btnGet;
    private EditText textName;
    private EditText textScore;
    private ViewGroup buttonLayout, inputLayout, listViewLayout;
    private ListView listScore;
    private View btnOK;
    private View btnCancel;

    private ArrayList<HighScore> scores;
    private MySharedPreference sharedPreference;
    private HashSet<String> scoreset;
    private Gson gson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //scores = new ArrayList<HighScore>();
        gson = new Gson();
        sharedPreference = new MySharedPreference(getApplicationContext());
        getHighScoreListFromSharedPreference();
        findView();

        //set event for buttons
        btnAdd.setOnClickListener(onAddListener());
        btnGet.setOnClickListener(onGettingDataListener());
        btnOK.setOnClickListener(onConfirmListener());
        btnCancel.setOnClickListener(onCancelListener());
    }

    private void findView() {
        listScore = (ListView)findViewById(R.id.list);
        buttonLayout = (ViewGroup)findViewById(R.id.layout_add);
        inputLayout = (ViewGroup)findViewById(R.id.layout_input);
        btnAdd = findViewById(R.id.btn_add);
        btnGet = findViewById(R.id.btn_get);
        btnOK = findViewById(R.id.btn_ok);
        btnCancel = findViewById(R.id.btn_cancel);
        textName = (EditText)findViewById(R.id.txt_name);
        textScore = (EditText)findViewById(R.id.txt_score);
        listViewLayout = (ViewGroup)findViewById(R.id.layout_listview);
    }

    /**
     * Save list of scores to own sharedpref
     * @param scoresList
     */
    private void saveScoreListToSharedpreference(ArrayList<HighScore> scoresList) {
        //convert ArrayList object to String by Gson
        String jsonScore = gson.toJson(scoresList);

        //save to shared preference
        sharedPreference.saveHighScoreList(jsonScore);
    }

    /**
     * Retrieving data from sharepref
     */
    private void getHighScoreListFromSharedPreference() {
        //retrieve data from shared preference
        String jsonScore = sharedPreference.getHighScoreList();
        Type type = new TypeToken<List<HighScore>>(){}.getType();
        scores = gson.fromJson(jsonScore, type);

        if (scores == null) {
            scores = new ArrayList<>();
        }
    }

    private View.OnClickListener onAddListener() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                listViewLayout.setVisibility(View.GONE);
                inputLayout.setVisibility(View.VISIBLE);
            }
        };
    }

    private View.OnClickListener onGettingDataListener() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (scores.size() == 0) {
                    Toast.makeText(MainActivity.this, "No data in sharedPreferences", Toast.LENGTH_SHORT).show();
                } else {
                    getHighScoreListFromSharedPreference(); //get data
                    //set adapter for listview and visible it
                    ListViewAdapter adapter = new ListViewAdapter(MainActivity.this, R.layout.item_listview, scores);
                    listScore.setAdapter(adapter);
                    listViewLayout.setVisibility(View.VISIBLE);
                    inputLayout.setVisibility(View.GONE);
                }
            }
        };
    }

    private View.OnClickListener onConfirmListener() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!textScore.getText().toString().equals("") && !textName.getText().toString().equals("")) {
                    //not null input
                    HighScore highScore = new HighScore();
                    highScore.setScore(textScore.getText().toString());
                    highScore.setPlayerName(textName.getText().toString());
                    scores.add(highScore); //add to scores list
                    saveScoreListToSharedpreference(scores); //save to share pref

                    //clear edit text data
                    textName.setText("");
                    textScore.setText("");
                } else {
                    Log.e("Activity", "null input");
                }

            }
        };
    }

    private View.OnClickListener onCancelListener() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //gone input layout
                inputLayout.setVisibility(View.GONE);
            }
        };
    }
}

4. Adding some necessary files:

- A ListView adapter extends from ArrayAdapter:
ListViewAdapter.java
package info.devexchanges.storelistofobjectsbygson;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.util.List;

public class ListViewAdapter extends ArrayAdapter<HighScore> {

    private Activity activity;

    public ListViewAdapter(Activity activity, int resource, List<HighScore> scores) {
        super(activity, resource, scores);
        this.activity = activity;

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder = null;
        LayoutInflater inflater = (LayoutInflater) activity
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        // If holder not exist then locate all view from UI file.
        if (convertView == null) {
            // inflate UI from XML file
            convertView = inflater.inflate(R.layout.item_listview, parent, false);
            // get all UI view
            holder = new ViewHolder(convertView);
            // set tag for holder
            convertView.setTag(holder);
        } else {
            // if holder created, get tag from view
            holder = (ViewHolder) convertView.getTag();
        }

        HighScore score = getItem(position);

        holder.playerName.setText(score.getPlayerName());
        holder.score.setText(score.getScore());

        return convertView;
    }

    private static class ViewHolder {
        private TextView playerName;
        private TextView score;

        public ViewHolder(View v) {
            playerName = (TextView) v.findViewById(R.id.name);
            score = (TextView) v.findViewById(R.id.score);
        }
    }
}
- Strings resource:
strings.xml
<resources>
    <string name="app_name">List Object In SharePreferences</string>

    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="add">Saving Score</string>
    <string name="get">Scores List</string>
    <string name="name">Player Name</string>
    <string name="ok">OK</string>
    <string name="list_header">High scores</string>
    <string name="cancel">Cancel</string>
    <string name="score">Player Score</string>
</resources>

5. Output after running application:


6. References

- Gson Project in on Githubhttps://github.com/google/gson
- Gson on Maven Center: http://search.maven.org/#browse%7C472424538
- SharedPreferences on Google doc

Share


Previous post
« Prev Post
Next post
Next Post »