Easy Tutorial
❮ Verilog2 Slow2Fast Es6 Async ❯

6.2 Data Storage and Access - SharedPreferences for Saving User Preferences

Category Android Basic Tutorial

Introduction:

>

This section introduces the second method of storing user data, using SharedPreferences (for saving user preferences) to store data. When our application needs to save some user preference parameters, such as whether to auto-login, remember account and password, or connect only under Wifi, using a database would be overkill. We refer to these configuration settings as user preferences, which are typically stored in specific files. For example, Windows uses ini files, J2SE uses properties files and XML files for software configuration, and in Android, we usually use a lightweight storage class - SharedPreferences to save user preference parameters. SharedPreferences also uses XML files and stores data in a key-value format, similar to a Map collection. We can retrieve values using SharedPreferences' getXxx(name) method, which is very convenient.


1. SharedPreferences Usage Example:

Flowchart:

Code Example:

Runtime Effect Diagram:

The process involves entering the account and password, clicking login, saving the information to the SharedPreference file, and then restarting the app to see that the data is displayed in the text boxes.

After saving, we can open data/data/<package name> in File Explorer and see an XML file generated in the shared_prefs directory (due to the N5 not being rooted, an older effect diagram is used here):

Clicking export to the desktop shows the contents:

Code Implementation:

Layout file activity_main.xml writing:

<LinearLayout 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:orientation="vertical"
    tools:context=".MyActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="User Login" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Please enter username" />

    <EditText
        android:id="@+id/editname"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Username" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Please enter password" />

    <EditText
        android:id="@+id/editpasswd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Password"
        android:inputType="textPassword" />

    <Button
        android:id="@+id/btnlogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login" />
</LinearLayout>

Writing a simple SP utility class: SharedHelper.java:

/**
 * Created by Jay on 2015/9/2 0002.
 */
public class SharedHelper {

    private Context mContext;

    public SharedHelper() {
    }

    public SharedHelper(Context mContext) {
        this.mContext = mContext;
    }

    // Method to save data
    public void save(String username, String passwd) {
        SharedPreferences sp = mContext.getSharedPreferences("mysp", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("username", username);
        editor.putString("passwd", passwd);
        editor.commit();
        Toast.makeText(mContext, "Information has been written to SharedPreference", Toast.LENGTH_SHORT).show();
    }

    // Method to read from SP file
    public Map&lt;String, String> read() {
        Map&lt;String, String> data = new HashMap&lt;String, String>();
        SharedPreferences sp = mContext.getSharedPreferences("mysp", Context.MODE_PRIVATE);
        data.put("username", sp.getString("username", ""));
        data.put("passwd", sp.getString("passwd", ""));
        return data;
    }
}

Finally, MainActivity.java implements the relevant logic:

public class MainActivity extends AppCompatActivity {

    private EditText editname;
    private EditText editpasswd;
    private Button btnlogin;
    private String strname;
    private String strpasswd;
    private SharedHelper sh;
    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = getApplicationContext();
        sh = new SharedHelper(mContext);
        bindViews();
    }

    private void bindViews() {
        editname = (EditText)findViewById(R.id.editname);
        editpasswd = (EditText)findViewById(R.id.editpasswd);
        btnlogin = (Button)findViewById(R.id.btnlogin);
        btnlogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                strname = editname.getText().toString();
                strpasswd = editpasswd.getText().toString();
                sh.save(strname,strpasswd);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Map<String,String> data = sh.read();
        editname.setText(data.get("username"));
        editpasswd.setText(data.get("passwd"));
    }
}

2. Reading Another Application's SharedPreferences

>

Core: To obtain another app's Context, which represents an interface to global information about an application environment, and the unique identifier of an application is its package name, so we can obtain the corresponding app's Context by its package name. Another point to note is that whether another application's SP file can be read or written depends on whether the SP file has specified readable or writable permissions. The MODE_PRIVATE we created earlier does not allow this. Therefore, it is difficult to read data from another's SP, and critical information like passwords stored in SP is usually encrypted, so it's mainly for self-use. We will discuss the commonly used MD5 encryption method later.

Implementation Flowchart:

Code Example:

Runtime Effect Diagram:

Code Implementation:

We perform the SP reading operation in MainActivity.java, and display it with a Toast after clicking the button:

public class MainActivity extends AppCompatActivity {

    private Context othercontext;
    private SharedPreferences sp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnshow = (Button) findViewById(R.id.btnshow);
btnshow.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Obtain the package name of the first application to get the corresponding Context, exception handling is required
        try {
            othercontext = createPackageContext("com.jay.sharedpreferencedemo", Context.CONTEXT_IGNORE_SECURITY);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        // Retrieve the SharedPreferences based on the Context
        sp = othercontext.getSharedPreferences("mysp", Context.MODE_WORLD_READABLE);
        String name = sp.getString("username", "");
        String passwd = sp.getString("passwd", "");
        Toast.makeText(getApplicationContext(), "SharedPreference from Demo1\nUsername: " + name + "\nPassword: " + passwd, Toast.LENGTH_SHORT).show();
    }
});

3. Encrypting Important Data in SharedPreference with MD5

Hey, above we stored the account and password directly in SharedPreferences. If the phone isn't rooted, other apps can't access the data. But if it's rooted and data is accessed by other apps, leading to consequences, well... that's not our fault, haha. You rooted it yourself! We're not taking that blame. True, but as responsible app developers, we shouldn't do that, right? We can use encryption algorithms to encrypt user passwords. Typically, the passwords are what we encrypt. Below is a simple diagram to help understand the encryption process:

1. Simple Encryption Process

Flowchart:

Flowchart Explanation:

Got it? There are many encryption methods. I'm not an expert in this area, but I've used MD5 encryption before. This section briefly introduces MD5 encryption and demonstrates its usage.

2. Brief Introduction to MD5:

1) What is MD5?

Answer: Message Digest Algorithm MD5 (MD5) is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value. It's used to ensure data integrity. In simpler terms, it's an encryption algorithm that converts a string or file into a fixed 128-bit hash, which is almost unique. Since one hexadecimal digit requires 4 bits, the MD5 string length is 128 / 4 = 32 characters. Sometimes you might see a 16-character MD5 hash, which is the 32-character hash with the first and last 8 characters removed. You can test this on an MD5 decryption site like http://www.cmd5.com/.

2) Can MD5 be cracked?

Answer: MD5 is not reversible, meaning there's no algorithm to reverse an MD5 hash back to the original data. However, brute force attacks can crack simple MD5 hashes by comparing them to a database of known hashes.

3) Is the MD5 hash unique?

Answer: No, a single piece of original data corresponds to one MD5 hash, but one MD5 hash might correspond to multiple pieces of original data.


3. MD5 Encryption Example:

There are many MD5 examples online. Here's a tool class for MD5 encryption that I use:

Md5Util.java:

public class MD5 {
    public static String getMD5(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(content.getBytes());
            return getHashString(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getHashString(MessageDigest digest) {
        StringBuilder builder = new StringBuilder();
        for (byte b : digest.digest()) {
            builder.append(Integer.toHexString((b >> 4) & 0xf));
            builder.append(Integer.toHexString(b & 0xf));
        }
        return builder.toString();
    }
}

MainActivity.java calls the static method getMD5:

Log.e("HeHe", MD5.getMD5("呵呵"));

This is the encrypted "呵呵". You can copy this hash to an MD5 decryption site:

If you want more security, you can encrypt the hash 100 times. Here's a method to do that:

public static String getMD5x100(String content){
    String s1 = content;
    for(int i = 0;i < 100;i++){
        s1 = getMD5(s1);
    }
    return s1;
}

Calling this method results in a very long hash that's difficult to crack:


4. SharedPreference Utility Class:

It's cumbersome to manually instantiate SharedPreferences classes every time. Here's a utility class for SharedPreferences from a blog by a respected developer:

SPUtils.java:

public class SPUtils {
    public static final String FILE_NAME = "my_sp";

    public static void put(Context context, String key, Object obj) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        if (obj instanceof Boolean) {
            editor.putBoolean(key, (Boolean) obj);
        } else if (obj instanceof Float) {
            editor.putFloat(key, (Float) obj);
        } else if (obj instanceof Integer) {
            editor.putInt(key, (Integer) obj);
        } else if (obj instanceof Long) {
            editor.putLong(key, (Long) obj);
        } else {
            editor.putString(key, (String) obj);
        }
        editor.commit();
    }

    public static Object get(Context context, String key, Object defaultObj) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        if (defaultObj instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObj);
        } else if (defaultObj instanceof Float) {
            return sp.getFloat(key, (Float) defaultObj);
        } else if (defaultObj instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObj);
        } else if (defaultObj instanceof Long) {
            return sp.getLong(key, (Long) defaultObj);
        } else {
            return sp.getString(key, (String) defaultObj);
        }
    }
}
} else if (defaultObj instanceof Long) {
    return sp.getLong(key, (Long) defaultObj);
} else if (defaultObj instanceof String) {
    return sp.getString(key, (String) defaultObj);
}
return null;
}

/**
 * Delete specified data
 */
public static void remove(Context context, String key) {
    SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sp.edit();
    editor.remove(key);
    editor.commit();
}

/**
 * Return all key-value pairs
 */
public static Map&lt;String, ?> getAll(Context context) {
    SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
    Map&lt;String, ?> map = sp.getAll();
    return map;
}

/**
 * Delete all data
 */
public static void clear(Context context) {
    SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sp.edit();
    editor.clear();
    editor.commit();
}

/**
 * Check if data for the given key exists
 */
public static boolean contains(Context context, String key) {
    SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
    return sp.contains(key);
}

}

5. Code Download:

SharedPreferenceDemo.zip: Download SharedPreferenceDemo.zip
SharedPreferenceDemo2.zip: Download SharedPreferenceDemo2.zip
SharedPreferenceDemo3.zip: Download SharedPreferenceDemo3.zip


Summary:

>

That's all about the second method of storing data in Android: SharedPreference for saving user preferences. This should cover your needs for using SharedPreferences in your daily development. If anything is missing, please feel free to suggest. Thank you!

-1.0 Android Basic Beginner Tutorial

-1.0.1 2015 Latest Android Basic Beginner Tutorial Table of Contents

-1.1 Background and System Architecture Analysis

-1.2 Development Environment Setup

-1.2.1 Using Eclipse + ADT + SDK to Develop Android APP

-1.2.2 Using Android Studio to Develop Android APP

-1.3 Solving SDK Update Issues

-1.4 Genymotion Emulator Installation

-1.5.1 Git Tutorial for Basic Local Repository Operations

-1.5.2 Git: Setting Up a Remote Repository on GitHub

-1.6 How to Use 9-Patch Images

-1.7 Interface Prototype Design

-1.8 Project Source Analysis (Various Files, Resource Access)

-1.9 Android Application Signing and Packaging

-1.11 Decompiling APK to Retrieve Code & Resources

-2.1 Concepts of View and ViewGroup

-2.2.1 LinearLayout (Linear Layout)

-2.2.2 RelativeLayout (Relative Layout)

-2.2.3 TableLayout (Table Layout)

-2.2.4 FrameLayout (Frame Layout)

-2.2.5 GridLayout (Grid Layout)

-2.2.6 AbsoluteLayout (Absolute Layout)

-2.3.1 TextView (Text View) Detailed Explanation

-2.3.2 EditText (Input Box) Detailed Explanation

-2.3.3 Button and ImageButton

-2.3.4 ImageView (Image View)

-2.3.5.RadioButton (Radio Button) & Checkbox (Checkbox)

-2.3.6 ToggleButton and Switch

-2.3.7 ProgressBar (Progress Bar)

-2.3.8 SeekBar (Drag Bar)

-2.3.9 RatingBar (Star Rating Bar)

-2.4.1 ScrollView (Scroll Bar)

-2.4.2 Date & Time Components (Part 1)

-2.4.3 Date & Time Components (Part 2)

-2.4.4 Adapter Basics

-2.4.5 ListView Basic Usage

-2.4.6 BaseAdapter Optimization

-2.4.7 ListView Focus Issues

-2.4.8 Solving ListView Checkbox Misalignment Issues

-2.4.9 ListView Data Update Issues

-2.5.0 Building a Reusable Custom BaseAdapter

-2.5.1 Implementing Multi-Layout ListView Items

-2.5.2 GridView (Grid View) Basic Usage

-2.5.3 Spinner (List Option Box) Basic Usage

-2.5.4 AutoCompleteTextView (Auto-Complete Text Box) Basic Usage

-2.5.5 ExpandableListView (Collapsible List) Basic Usage

-2.5.6 ViewFlipper (Flip View) Basic Usage

-2.5.7 Toast Basic Usage

-2.5.8 Notification (Status Bar Notification) Detailed Explanation

-2.5.9 AlertDialog (Dialog Box) Detailed Explanation ``` -2.6.0 Basic Usage of Several Common Dialogs

-2.6.1 Basic Usage of PopupWindow (Floating Box)

-2.6.2 Menu

-2.6.3 Simple Usage of ViewPager

-2.6.4 Simple Usage of DrawerLayout (Official Side Sliding Menu)

-3.1.1 Event Handling Mechanism Based on Listeners

-3.2 Event Handling Mechanism Based on Callbacks

-3.3 Analysis of Handler Message Passing Mechanism

-3.4 TouchListener vs OnTouchEvent + Multi-touch

-3.5 Listening for Content Changes in EditText

-3.6 Responding to System Setting Events (Configuration Class)

-3.7 AsyncTask Asynchronous Task

-3.8 Gestures

-4.1.1 Introduction to Activity

-4.1.2 Getting Started with Activity

-4.1.3 Advanced Activity

-4.2.1 Introduction to Service

-4.2.2 Intermediate Service

-4.2.3 Advanced Service

-4.3.1 Introduction to BroadcastReceiver

-4.3.2 In-depth BroadcastReceiver

-4.4.1 Introduction to ContentProvider

-4.4.2 Further Exploration of ContentProvider - Document Provider

-4.5.1 Basic Usage of Intent

-4.5.2 Passing Complex Data with Intent

-5.1 Basic Overview of Fragment

-5.2.1 Fragment Example Analysis - Bottom Navigation Bar Implementation (Method 1)

-5.2.2 Fragment Example Analysis - Bottom Navigation Bar Implementation (Method 2)

-5.2.3 Fragment Example Analysis - Bottom Navigation Bar Implementation (Method 3)

-5.2.4 Fragment Example Analysis - Bottom Navigation Bar + ViewPager Swipe to Switch Pages

-5.2.5 Fragment Example Analysis - Simple Implementation of News (Shopping) App List Fragment

-6.1 Data Storage and Access - File Storage and Reading

-6.3.1 Data Storage and Access - Introduction to SQLite Database

-6.3.2 Data Storage and Access - Further Exploration of SQLite Database

-7.1.1 Android Network Programming Essentials and Learning HTTP Protocol

-7.1.2 Learning Android HTTP Request Headers and Response Headers

-7.1.3 Android HTTP Request Method: HttpURLConnection

-7.1.4 Android HTTP Request Method: HttpClient

-7.2.1 Android XML Data Parsing

-7.2.2 Android JSON Data Parsing

-7.3.1 Android File Upload

-7.3.2 Android File Download (1)

-7.3.3 Android File Download (2)

-7.4 Android Calling WebService

-7.5.1 Basic Usage of WebView (Web View)

-7.5.2 Basic Interaction Between WebView and JavaScript

-7.5.3 Important Considerations for WebView in Android 4.4 and Later

-7.5.4 WebView File Download

-7.5.5 WebView Cache Issues

-7.5.6 WebView Handling Error Code Information from Web Pages

-7.6.1 Network Basics Preparation for Socket Learning

-7.6.2 Socket Communication Based on TCP Protocol (1)

-7.6.3 Socket Communication Based on TCP Protocol (2)

-7.6.4 Socket Communication Based on UDP Protocol

-8.1.1 Summary of 13 Drawable Types in Android Part 1

-8.1.2 Summary of 13 Drawable Types in Android Part 2

-8.1.3 Summary of 13 Drawable Types in Android Part 3

-8.2.1 Comprehensive Analysis of Bitmap (Bitmap) Part 1

-8.2.2 OOM Issues Caused by Bitmap

-8.3.1 Detailed Explanation of Three Drawing Tool Classes

-8.3.2 Practical Examples of Drawing Classes

-8.3.3 Paint API - MaskFilter (Mask)

-8.3.4 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 1)

-8.3.5 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 2)

-8.3.6 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 3)

-8.3.7 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 4)

-8.3.8 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 5)

-8.3.9 Paint API - ColorFilter (Color Filter) (1/3)

-8.3.10 Paint API - ColorFilter (Color Filter) (2/3)

-8.3.11 Paint API - ColorFilter (Color Filter) (3/3)

-8.3.12 Paint API - PathEffect (Path Effect)

-8.3.13 Paint API - Shader (Image Rendering)

-8.3.14 Paint Enum/Constant Values and ShadowLayer Shadow Effect

-8.3.15 Paint API - Typeface (Font Style)

WeChat Subscription

❮ Verilog2 Slow2Fast Es6 Async ❯