文章目录
- 文件存储
- SharedPreferences存储
-
- 存储
-
- 获取SharedPreferences对象
- [Context 类的 getSharedPreferences() 方法](#Context 类的 getSharedPreferences() 方法)
-
- [Activity 类的 getPreferences() 方法](#Activity 类的 getPreferences() 方法)
- [PreferenceManager 类中的 getDefaultSharedPreferences() 方法](#PreferenceManager 类中的 getDefaultSharedPreferences() 方法)
- 示例
- 读取
- 记住密码的功能
- SQLite数据库存储
今天来介绍一下Android的数据持久化技术,提供了三种存储方式,还可以存储到SD卡中。
主要介绍这三种:
文件存储
适用于存储较大或复杂的数据文件,比如图像、视频、文档等。
也适合存储简单的文本文件。
SharedPreferences存储
适用于存储简单的键值对数据,比如用户设置和应用配置。
数据量通常较小,数据结构简单。
数据库存储
适用于存储结构化数据,支持复杂的查询和数据管理。
文件存储
使用Context
提供的openFileOutput
和openFileInput
方法,他们返回
存储到文件
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() 方法
步骤:
- 获取
SharedPreferences.Editor
编辑器对象通过
SharedPreferences
对象的edit()
方法
向
SharedPreferences
中存储数据提交数据
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();
}
-
获取
SharedPreferences
编辑器对象:javaSharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
getSharedPreferences("data", MODE_PRIVATE)
:获取名为data
的SharedPreferences
文件。MODE_PRIVATE
:操作模式,表示只有本应用可以访问此文件。edit()
:获取SharedPreferences.Editor
对象,用于修改SharedPreferences
。
-
向
SharedPreferences
中存储数据:javaeditor.putString("name", "feng"); editor.putInt("age", 20); editor.putBoolean("married", false);
putString("name", "feng")
:存储一个字符串键值对。putInt("age", 20)
:存储一个整数键值对。putBoolean("married", false)
:存储一个布尔键值对。
-
提交数据:
javaeditor.apply();
apply()
:异步提交数据,不会返回任何结果,更加高效。可以使用commit()
同步提交数据,但会返回一个布尔值表示提交是否成功。
读取
get方法:允许你根据键(key)从 SharedPreferences
文件中获取相应的值
getString
,getInt
,getBoolean
,getFloat
,getLong
,getStringSet
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
构造方法javapublic MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); mContext = context; }
-
Context
:在构造函数中,这个参数用于初始化mContext
,以便在数据库创建时(例如在onCreate
方法中)显示Toast消息或访问其他资源 -
String
:指定你想要创建或打开的数据库文件的名称。数据库文件会保存在应用的默认数据库目录中(通常是/data/data/<package_name>/databases/
) -
SQLiteDatabase.CursorFactory
:作用 : 这是一个
SQLiteDatabase.CursorFactory
对象,用于创建Cursor
对象。这个工厂对象可以用于自定义Cursor
的创建方式,但通常不需要使用它,默认值为null
。使用 : 你可以传递一个自定义的
CursorFactory
对象,以便自定义Cursor
的行为。如果不需要自定义,可以传递null
,这时SQLite会使用默认的CursorFactory
。 -
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
方法添加数据javaContentValues 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();
}
});
感谢您的阅读
如有错误烦请指正
参考:
- 《第一行代码》