全部开发者教程

Android 入门教程

菜单类控件
菜单:Menu
并发编程
多线程

SharedPreferences 存储

上一节学习了文件存储方式,基本上所有的数据我们都可以通过文件去存,但是整体操作起来会比较麻烦,而且没有一个通用固定的数据结构,如果只需要存储一些轻量级的东西,比如“用户偏好”、“系统设置”、“开关值”等相关数据可能只需要一个 Boolean 或者一个 Int 即可,那么 SharedPreferences 则是一个非常轻量简单的选择。

1. SharedPreferences 特点

在 Android 中,Shared Preferences 专门用于存储一些基本数据类型(integer, float, boolean, string, long),它通过一种Key-Value的数据结构存储在私有目录中。
我们可以通过 Shared Preferences 的接口获取一个指向 Key-Value 文件的对象,相比操作文件可以更轻松的通过 Shared Preferences 进行数据的读取和写入。该接口由 Android 系统负责管理,我们可以在任何地方通过接口操作 Shared Preferences,而且只有自己的 App 能够访问,是比较安全的存储方式,非常适合存储一些轻量级的数据,类似“记住密码”、“自动登录”、“各种设置”的场景。

2. 处理 SharedPreferences

我们可以选择将所有的数据存在一个 SharedPreferences 文件中或者分成多个文件存储,取决于具体业务需求,系统提供了两个 Api 供我们使用:

  • getPreferences():
    Activity 级别的 API,系统会给每个 Activity 创建一个独立的 SharedPreferences 文件,各自 Activity 管理各自的数据。
  • getSharedPreferences():
    App 级别的 API,没有 Activity 的限制,通过传入的参数来决定用哪个 SharedPreferences 文件。

两种 API 的使用示例如下:

SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences sharedPref = getSharedPreferences("filename", Context.MODE_PRIVATE);

第二个 API 的 fileName 就告诉系统采用哪个 SharedPreferences 文件。

3. SharedPreferences 的读写

和 File 一样,SharedPreferences 的主要操作也是读写,不过相比之下 SharedPreferences 简单很多。

3.1 写入

为了将数据存储到 SharedPreferences 文件中,我们需要一个editor对象来编辑数据并保存到 SharedPreferences 对象中。下面是一段editor的使用示例代码:

SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean("keyb",true);
editor.putString("keys","string value");
editor.putInt("keyi","int value");
editor.putFloat("keyf","float value");
editor.putLong("keyl","long value");
editor.commit();

可以发现,我们是通过sharedPref.edit()方法来获取 editor 对象的,我们可以用 Key-Value 的形式添加一些基本类型变量,最后通过commit()方法提交即可。

3.2 读取

在写入之后,我们可以通过以下方式进行数据读取:

SharedPreferences pref = getPreferences(Context.MODE_PRIVATE);
pref.getString("keys",null);
pref.getInt("keyi",0);
pref.getFloat("keyf",0);
pref.getBoolean("keyb",true);
pref.getLong("keyl",0);

3.3 删除数据

虽然 SharedPreferences 保存的都是轻量级的数据,但是过多仍然会造成一些磁盘空间的占用,所以需要对于不用的数据进行及时的删除,可以通过remove ()接口进行删除。

SharedPreferences pref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.remove("key");
editor.commit();

3.4 清空

我们还可以通过clear()接口直接清空所有数据:

SharedPreferences pref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.clear();
editor.commit();

记得在使用“editor”对象的相关操作之后,一定要调用commit()方法将修改进行 提交。

4. SharedPreferences 使用示例

本节来做一个登录页面,我们通过 SharedPreferences 来记录当前的登陆状态,只要用户成功登陆过,那么下次登录我们会读取 SharedPreferences,一旦发现已登录就可以免登陆直接进入登录态,这也是一个很常见的场景。

4.1 登录页面的编写

登录页面就是主页的 XML 布局文件,核心就是两个输入框,分别对应“账号”和“密码”,另外就是一个确认登录的 Button。

<?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="vertical">

    <TextView
        android:id="@+id/account"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:layout_marginTop="150dp"
        android:text="账号:" />

    <EditText
        android:id="@+id/et_account"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:ems="10" />

    <TextView
        android:id="@+id/password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:text="密码:" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="100dp"
        android:ems="10"
        android:inputType="textPassword" />

    <Button
        android:id="@+id/login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:text="登录" />
</LinearLayout>

登录界面如下:

login

4.2 登录 Activity

登录的逻辑主要是匹配账号和密码,如果通过我们记录一个登陆成功的 Key-Value 到 SharedPreferences 中,然后跳转到登录成功的页面即可。

package com.emercy.myapplication;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
    EditText userName, pwd;
    Button loginBtn;
    SharedPreferences pref;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        userName = findViewById(R.id.et_account);
        pwd = findViewById(R.id.et_password);
        loginBtn = findViewById(R.id.login);
        pref = getSharedPreferences("user_details", MODE_PRIVATE);
        final Intent intent = new Intent(MainActivity.this, SecondActivity.class);
        
        // 1、检查是否登录成功
        if (pref.contains("username") && pref.contains("password")) {
            startActivity(intent);
        }
        loginBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 2、输入账号密码
                String username = userName.getText().toString();
                String password = pwd.getText().toString();
                if (username.equals("超低空") && password.equals("慕课网")) {
                    SharedPreferences.Editor editor = pref.edit();
                    editor.putString("username", username);
                    editor.putString("password", password);
                    editor.commit();
                    Toast.makeText(getApplicationContext(), "登陆成功", Toast.LENGTH_SHORT).show();
                    // 3、账号密码正确,跳转                  
                    startActivity(intent);
                } else {
                    // 4、输入错误
                    Toast.makeText(getApplicationContext(), "账号或者密码错误", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

首先我们检查已经登录成功过,是就直接跳转,否则等待用户输入账号密码,在登录成功之后写入 SharePreferenced 并跳转。

4.3 登录后的页面

创建second.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="vertical">

    <TextView
        android:id="@+id/result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="170dp"
        android:textSize="20sp" />

    <Button
        android:id="@+id/logout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="注销登录" />
</LinearLayout>

主要是一个欢迎页面,带上了用户的账号名,另外就是一个“注销登录”按钮,可以删除登录记录并跳转回登录首页,登陆成功后页面如下:

logout

4.4 登录后的逻辑控制

登录后需要实现一个欢迎标语以及注销的逻辑:

package com.emercy.myapplication;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class SecondActivity extends Activity {
    SharedPreferences sharedPreferences;
    Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second);
        TextView result = findViewById(R.id.result);
        Button btnLogOut = findViewById(R.id.logout);
        sharedPreferences = getSharedPreferences("user_details", MODE_PRIVATE);
        intent = new Intent(SecondActivity.this, MainActivity.class);
        result.setText("欢迎您, " + sharedPreferences.getString("username", null));
        btnLogOut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.clear();
                editor.commit();
                startActivity(intent);
            }
        });
    }
}

5. 小结

本节学习了第二个存储方式,SharedPreferences 相比 File 更加轻量简单,适合于存储一些基础类型的 Key-Value 对。比如“设置”、“开关”、“登录”等等场景,根据不同的业务场景我们可以选择将不同的数据放在不同的 SharedPreferences 文件中,然后通过系统 API 进行增删改查,对于轻量级数据来讲是个非常不错的选择。