【Android】数据存储方案——文件存储、SharedPreferences、SQLite数据库用法总结

文章目录

今天来介绍一下Android的数据持久化技术,提供了三种存储方式,还可以存储到SD卡中。

主要介绍这三种:

文件存储

适用于存储较大或复杂的数据文件,比如图像、视频、文档等。

也适合存储简单的文本文件。

SharedPreferences存储

适用于存储简单的键值对数据,比如用户设置和应用配置。

数据量通常较小,数据结构简单。

数据库存储

适用于存储结构化数据,支持复杂的查询和数据管理。

文件存储

使用Context提供的openFileOutputopenFileInput方法,他们返回

存储到文件

openFileOutput()

java 复制代码
public class MainActivity extends AppCompatActivity {

    private EditText edit; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit = findViewById(R.id.editText); 
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = edit.getText().toString();  // 获取EditText中的文本
        save(inputText);  
    }

    // 将输入的文本保存到文件的方法
    private void save(String inputText) {
        FileOutputStream out = null;  // 声明FileOutputStream变量
        BufferedWriter writer = null;  // 声明BufferedWriter变量
        try {
            // 打开名为 "data" 的文件
            out = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(out));  // 创建BufferedWriter对象
            writer.write(inputText);  // 将输入的文本写入文件
        } catch (IOException e) {
            throw new RuntimeException(e); 
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e); 
            }
        }
    }
}

读取文件

openFileInput

java 复制代码
public class MainActivity extends AppCompatActivity {

    private EditText edit; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        
        edit = findViewById(R.id.editText);
        
        String inputText = load(); 
        // 如果加载到的文本内容不为空
        if (!TextUtils.isEmpty(inputText)) { 
            // 如果加载到的文本内容不为空
            edit.setText(inputText); 
            // 将光标移动到文本末尾
            edit.setSelection(inputText.length()); 
            Toast.makeText(this, "加载成功", Toast.LENGTH_SHORT).show(); 
           
        }
    }

    // 加载之前保存的文本内容
    private String load() {
        FileInputStream input = null; 
        BufferedReader reader = null;
        // 创建 StringBuilder 对象,用于存储加载的文本内容
        StringBuilder content = new StringBuilder(); 
        try {
            // 打开名为 "data" 的文件
            input = openFileInput("data"); 
            // 创建 BufferedReader 对象
            reader = new BufferedReader(new InputStreamReader(input)); 
            String line;
            while ((line = reader.readLine()) != null) { 
                content.append(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (reader != null) {
                    reader.close(); 
                }
            } catch (IOException e) {
                throw new RuntimeException(e); 
            }
        }
        return content.toString(); 
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = edit.getText().toString();
        save(inputText); 
    }

  
    private void save(String inputText) {
        //省略
    }
}

SharedPreferences存储

存储

获取SharedPreferences对象

利用SharedPreferences来存储数据,有三种获取SharedPreferences对象的方法

Context 类的 getSharedPreferences() 方法

  • 第一个参数指定SharedPreferences文件名
  • 第二个参数指定操作模式,MODE_PRIVATE:只有当前应用程序可以对SharedPreferences文件读写
java 复制代码
SharedPreferences sharedPreferences = getSharedPreferences("data", MODE_PRIVATE);
Activity 类的 getPreferences() 方法
  • 只接受一个操作模式

  • 自动使用当前应用程序包名作为前缀命名SharedPreferences文件

java 复制代码
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
PreferenceManager 类中的 getDefaultSharedPreferences() 方法

步骤:

  1. 获取 SharedPreferences.Editor 编辑器对象

通过SharedPreferences对象的edit()方法

  1. SharedPreferences 中存储数据

  2. 提交数据

java 复制代码
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPreferences.edit();

或者

java 复制代码
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();

示例

java 复制代码
public void StoringData(View view) {
    // 获取 SharedPreferences 编辑器对象
    SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();

    // 向 SharedPreferences 中存储数据
    editor.putString("name", "feng"); // 存储一个字符串值
    editor.putInt("age", 20); // 存储一个整数值
    editor.putBoolean("married", false); // 存储一个布尔值

    // 提交数据
    editor.apply();
}
  1. 获取 SharedPreferences 编辑器对象

    java 复制代码
    SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
    • getSharedPreferences("data", MODE_PRIVATE):获取名为 dataSharedPreferences 文件。
    • MODE_PRIVATE:操作模式,表示只有本应用可以访问此文件。
    • edit():获取 SharedPreferences.Editor 对象,用于修改 SharedPreferences
  2. SharedPreferences 中存储数据

    java 复制代码
    editor.putString("name", "feng");
    editor.putInt("age", 20);
    editor.putBoolean("married", false);
    • putString("name", "feng"):存储一个字符串键值对。
    • putInt("age", 20):存储一个整数键值对。
    • putBoolean("married", false):存储一个布尔键值对。
  3. 提交数据

    java 复制代码
    editor.apply();
    • apply():异步提交数据,不会返回任何结果,更加高效。可以使用 commit() 同步提交数据,但会返回一个布尔值表示提交是否成功。

读取

get方法:允许你根据键(key)从 SharedPreferences 文件中获取相应的值

getStringgetIntgetBooleangetFloatgetLonggetStringSet

java 复制代码
getStringSet(String key, Set<String> defValues)
  • 获取一个字符串集合
  • 第一个参数:键
  • 第二个参数:键不存在,返回的默认值
java 复制代码
public void readData(View view) {
    // 获取 SharedPreferences 对象
    SharedPreferences sharedPreferences = getSharedPreferences("data", MODE_PRIVATE);
    
    // 读取数据
    String name = sharedPreferences.getString("name", ""); 
    int age = sharedPreferences.getInt("age", 0); 
    boolean married = sharedPreferences.getBoolean("married", false); 
    
    // 打印读取到的数据
    Log.d("SecondActivity", "name: " + name + " age: " + age + " married: " + married);
}

记住密码的功能

展示登陆界面

记住密码:

java 复制代码
public class MainActivity extends BaseActivity {

    private EditText editText1;  // 用于输入账号的 EditText
    private EditText editText2;  // 用于输入密码的 EditText
    private Button btn;          // 用于触发登录的按钮
    private CheckBox rememberPass; // 用于是否记住密码的复选框
    private SharedPreferences sharedPreferences; // 用于存储和读取用户的登录信息
    private SharedPreferences.Editor editor; // 用于编辑 SharedPreferences 的数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 

        editText1 = findViewById(R.id.editText1);
        editText2 = findViewById(R.id.editText2);
        btn = findViewById(R.id.button);
        rememberPass = findViewById(R.id.remeber_pass);
        
        // 获取 SharedPreferences 对象,用于存储和读取数据
        sharedPreferences = getSharedPreferences("data", MODE_PRIVATE);

        // 检查 SharedPreferences 中是否保存了记住密码的设置
        Boolean isRemember = sharedPreferences.getBoolean("remember_password", false);
        if (isRemember) {
            // 如果记住密码被勾选,填充账号和密码的 EditText,并且勾选复选框
            editText1.setText(sharedPreferences.getString("account", ""));
            editText2.setText(sharedPreferences.getString("password", ""));
            rememberPass.setChecked(true);
        }

        // 登陆按钮点击事件监听器
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 获取用户输入的账号和密码
                String count = editText1.getText().toString();
                String password = editText2.getText().toString();
                
                // 验证账号和密码
                if (count.equals("feng") && password.equals("123")) {

                    // 获取 SharedPreferences 的编辑器对象,注意是在判断语句的外面的大
                    editor = sharedPreferences.edit();
                    
                    // 根据复选框的状态决定是否保存账号和密码
                    if (rememberPass.isChecked()) {
                        // 如果勾选了复选框,保存账号和密码
                        editor.putBoolean("remember_password", true);
                        editor.putString("account", editText1.getText().toString());
                        editor.putString("password", editText2.getText().toString());
                    } else {
                        // 如果未勾选复选框,清除保存的账号和密码
                        editor.clear();
                    }
  
                    // 应用编辑器的更改
                    editor.apply();

                    // 启动新的 Activity 并结束当前 Activity
                    Intent intent = new Intent(MainActivity.this, FirstActivity.class);
                    startActivity(intent);
                    finish();
                } else {
                    // 如果账号或密码错误,显示错误提示
                    Toast.makeText(MainActivity.this, "账号或密码错误", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

SQLite数据库存储

创建数据库

SQLiteOpenHelper抽象类,需要重写onCreate() onUpgrade()两个方法

自定义一个帮助类继承SQLiteOpenHelper

  • getReadableDatabase()getWritableDatabase()

    都可以创建或打开一个现有的数据库(没有就新创建一个)

    返回一个可以对新数据库进行读写操作的对象

  • SQLiteOpenHelper构造方法

    java 复制代码
     public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
            mContext = context;
        }
    1. Context:在构造函数中,这个参数用于初始化mContext,以便在数据库创建时(例如在onCreate方法中)显示Toast消息或访问其他资源

    2. String:指定你想要创建或打开的数据库文件的名称。数据库文件会保存在应用的默认数据库目录中(通常是/data/data/<package_name>/databases/

    3. SQLiteDatabase.CursorFactory

      作用 : 这是一个SQLiteDatabase.CursorFactory对象,用于创建Cursor对象。这个工厂对象可以用于自定义Cursor的创建方式,但通常不需要使用它,默认值为null

      使用 : 你可以传递一个自定义的CursorFactory对象,以便自定义Cursor的行为。如果不需要自定义,可以传递null,这时SQLite会使用默认的CursorFactory

    4. int version

      数据库的版本号。每次对数据库结构进行更改时,都需要增加这个版本号,以便触发onUpgrade方法。

    数据库创建代码示例:

java 复制代码
public class MyDatabaseHelper extends SQLiteOpenHelper {

    // SQL语句用于创建Book表
    public static final String CREATE_BOOK = "create table Book("
            + "id integer primary key autoincrement,"  // id字段,自增主键
            + "author text,"  // author字段,作者名称
            + "price real,"  // price字段,书的价格
            + "pages integer,"  // pages字段,书的页数
            + "name text)";  // name字段,书名

    private Context mContext;  // 用于显示Toast消息的Context对象

    // 构造函数,初始化数据库助手对象
    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);  // 调用父类构造函数
        mContext = context;  // 保存Context对象
    }

    // 创建数据库时调用,执行SQL语句创建表
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);  // 执行创建Book表的SQL语句
        db.execSQL(CREATE_CATEGORY);  // 执行创建Category表的SQL语句(注意CREATE_CATEGORY未定义)
        Toast.makeText(mContext, "创建成功", Toast.LENGTH_SHORT).show();  // 显示表创建成功的消息
    }

    // 升级数据库时调用,处理数据库版本升级
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
java 复制代码
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper databaseHelper;  // 数据库帮助类的实例
    private Button btn;  // 按钮控件的实例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        btn = findViewById(R.id.btn1);  

        // 初始化数据库帮助类
        databaseHelper = new MyDatabaseHelper(this, "BookStore", null, 1);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 获取可写的数据库实例
                databaseHelper.getWritableDatabase();
            }
        });
    }
}

升级数据库

因为oncreate方法只执行一次,当我们要更新数据库是无法成功

java 复制代码
public class MyDatabaseHelper extends SQLiteOpenHelper {

    // 定义创建 Book 表的 SQL 语句
    public static final String CREATE_BOOK = "create table Book("
            + "id integer primary key autoincrement,"  // 自增主键 id
            + "author text,"  // 作者
            + "price real,"  // 价格
            + "pages integer,"  // 页数
            + "name text)";  // 书名

    // 定义创建 Category 表的 SQL 语句
    public static final String CREATE_CATEGORY = "create table Category("
            + "id integer primary key autoincrement,"  // 自增主键 id
            + "category_name text,"  // 类别名称
            + "category_code integer)";  // 类别代码

    private Context mContext;  // 上下文对象

    // 构造函数,初始化数据库帮助类
    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;  // 初始化上下文
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 创建 Book 表
        db.execSQL(CREATE_BOOK);
        // 创建 Category 表
        db.execSQL(CREATE_CATEGORY);
        // 显示提示信息
        Toast.makeText(mContext, "创建成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 如果表存在,删除 Book 表
        db.execSQL("drop table if exists Book");
        // 如果表存在,删除 Category 表
        db.execSQL("drop table if exists Category");
        // 重新创建数据库
        onCreate(db);
    }
}

更新版本号,比刚才大,onUpgrade()就可以执行了

java 复制代码
        databaseHelper = new MyDatabaseHelper(this, "BookStore", null, 2);

添加数据

CRUD:创建(Create)、读取(Read)、更新(Update)和删除(Delete)

getReadableDatabase()getWritableDatabase()返回一个可以对新数据库进行读写操作的对象

调用该对象insert方法

insert

java 复制代码
long insert (String table, String nullColumnHack, ContentValues values)
  • table :要插入数据的表名,例如 "Book"

  • nullColumnHack

    未指定添加数据情况下给某些可为空的列自动赋值NULL,一般不使用该功能,直接传入null

  • values: 一个 ContentValues 对象,包含列名和相应的值。

    使用它的put方法添加数据

    java 复制代码
    ContentValues values = new ContentValues();
    values.put("name", "The Da Vinci Code");
    values.put("author", "Dan Brown");
    values.put("pages", 454);
    values.put("price", 16.96);

    添加数据示例:

java 复制代码
btn2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 获取可写的数据库实例
        SQLiteDatabase db = databaseHelper.getWritableDatabase();
        
        // 创建 ContentValues 实例并存储第一条记录的数据
        ContentValues values = new ContentValues();
        values.put("name", "The Da Vinci Code"); // 书名
        values.put("author", "Dan Brown"); // 作者
        values.put("pages", 454); // 页数
        values.put("price", 16.96); // 价格
        
        // 插入第一条记录到数据库的 "data" 表
        db.insert("Book", null, values);
        
        // 清空 ContentValues 实例并存储第二条记录的数据
        values.clear();
        values.put("name", "The Lost Symbol"); // 书名
        values.put("author", "Dan Brown"); // 作者
        values.put("pages", 510); // 页数
        values.put("price", 19.95); // 价格
        
        // 插入第二条记录到数据库的 "data" 表
        db.insert("Book", null, values);
        
        // 清空 ContentValues 实例以备将来使用
        values.clear();
    }
});

更新数据

与插入数据类似,最后使用update方法更新

  • 第一个参数:表名 "Book"
  • 第二个参数:ContentValues 对象,包含要更新的列及其新值
  • 第三个参数:WHERE 子句,指定哪些行需要更新,这里使用占位符 '?'
  • 第四个参数:占位符的实际值,这里是 "The Da Vinci Code"
java 复制代码
btn3.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 获取可写的数据库实例
        SQLiteDatabase db = databaseHelper.getWritableDatabase();
        
        // 创建 ContentValues 实例并存储要更新的列及其新值
        ContentValues values = new ContentValues();
        values.put("price", 150); // 更新书籍的价格为 150
        
        // 执行更新操作
        db.update("Book", values, "name = ?", new String[]{"The Da Vinci Code"});
    }
});

删除数据

delete方法

  • 第一个参数:表名 "Book"
  • 第二个参数:WHERE 子句,指定哪些行需要删除,这里使用占位符 '?'
  • 第三个参数:占位符的实际值,这里是 "500"
java 复制代码
btn4.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 获取可写的数据库实例
        SQLiteDatabase db = databaseHelper.getWritableDatabase();
        
        // 执行删除操作
        // 删除五百页以上的书
        db.delete("Book", "pages > ?", new String[]{"500"});
    }
});

查询数据

复制代码
  Cursor cursor = db.query("Book", null, null, null, null, null, null);
  • 第一个参数 "Book" 是要查询的表名。
  • 第二个参数 null 表示查询所有列。
  • 第三个到第六个参数 null 分别表示 WHERE 子句、WHERE 子句参数、GROUP BY 子句和 HAVING 子句,这里都没有使用。
  • 第七个参数 null 表示排序顺序,这里没有指定。
  • 处理查询结果:

    if (cursor.moveToFirst()) 检查游标是否包含数据,如果包含数据,则移动到第一行。
    *

    复制代码
      do {...} while (cursor.moveToNext());

    循环遍历游标中的所有行,读取每一行的数据,在这里使用 Log.d 方法将读取到的数据输出到日志中,方便调试和查看。

java 复制代码
btn5.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 获取可写的数据库实例
        SQLiteDatabase db = databaseHelper.getWritableDatabase();
        
        // 查询 "Book" 表中的所有数据
        Cursor cursor = db.query("Book", null, null, null, null, null, null);
        
        // 检查游标是否至少包含一行数据
        if (cursor.moveToFirst()) {
            do {
                // 读取当前行的数据
                String name = cursor.getString(cursor.getColumnIndex("name")); 
                // 读取 "name" 列的数据
                String author = cursor.getString(cursor.getColumnIndex("author")); 
                // 读取 "author" 列的数据
                int pages = cursor.getInt(cursor.getColumnIndex("pages")); 
                // 读取 "pages" 列的数据
                double price = cursor.getDouble(cursor.getColumnIndex("price")); 
                // 读取 "price" 列的数据
                
                // 打印读取的数据到日志
                Log.d("MainActivity", "book name is " + name);
                Log.d("MainActivity", "book author is " + author);
                Log.d("MainActivity", "book pages is " + pages);
                Log.d("MainActivity", "book price is " + price);
                
            } while (cursor.moveToNext()); // 移动到下一行数据
        }
        
        // 关闭游标
        cursor.close();
    }
});


感谢您的阅读
如有错误烦请指正


参考:

  1. 《第一行代码》
相关推荐
NCIN EXPE39 分钟前
redis 使用
数据库·redis·缓存
MongoDB 数据平台40 分钟前
为编码代理引入 MongoDB 代理技能和插件
数据库·mongodb
lUie INGA44 分钟前
在2023idea中如何创建SpringBoot
java·spring boot·后端
极客on之路1 小时前
mysql explain type 各个字段解释
数据库·mysql
代码雕刻家1 小时前
MySQL与SQL Server的基本指令
数据库·mysql·sqlserver
lThE ANDE1 小时前
开启mysql的binlog日志
数据库·mysql
yejqvow121 小时前
CSS如何控制placeholder文字的颜色_使用--placeholder伪元素
jvm·数据库·python
oLLI PILO1 小时前
nacos2.3.0 接入pgsql或其他数据库
数据库
geBR OTTE1 小时前
SpringBoot中整合ONLYOFFICE在线编辑
java·spring boot·后端
m0_743623921 小时前
HTML怎么创建多语言切换器_HTML语言选择下拉结构【指南】
jvm·数据库·python