一、持久化技术
1.数据持久化:
将内存中的瞬时数据保存到存储设备中。
2.持久化技术的三种方式:
文件存储、SharedPreferences存储、数据库存储
二、SharedPreferences存储
使用键值对的方式存储数据。读取数据时通过键把相应的值读出来
存储路径:存储位置在/data/data/<包名>/shared_prefs目录下
1.将数据存储到SharedPreferences中
要使用SharedPreferences来存储数据,首先要获得SharedPreferences对象。
SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现
获取SharedPreferences对象的三种方法:
1.Context类中的getSharedPreferences()方法
getSharedPreferences(String name, int mode):
- 第一个参数:指定SharedPerferences文件的名称,若指定的文件不存在则会创建一个。
- 第二个参数:指定操作模式。只有MODE_PRIVATE一种模式。
2.Activity类中的getPreferences()方法
getPreferences(int mode):参数为操作模式
使用该方法会自动将当前活动的类名作为SharedPreferences的文件名
3.PreferenceManager类中的getDefaultSharedPreferences()方法
getDefaultSharedPreferences(Context context):参数为context
存储数据步骤:
(1)SharedPreferences对象调用edit()方法得到SharedPreferences.Editor对象
(2)调用SharedPreferences.Editor对象的putInt()、putString()、putBoolean()等方法向SharedPreferences.Editor对象中添加数据
(3)调用apply()方法将添加的数据提交
activity_main.xml中设置一个按钮布局即可,这里省略
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = findViewById(R.id.button);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取SharedPreferences.Editor对象
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
//添加数据
editor.putString("name","Tom");
editor.putInt("age",25);
editor.putBoolean("married",false);
//提交
editor.apply();
}
});
}
方法解析:
getSharedPreferences(String name, int mode):指定存储数据的文件名并得到SharedPreferences对象
edit():获取SharedPreferences.Editor对象
putXXX(String var1,XXX var2):添加不同类型的数据。参数一是key值,参数二是value值
apply():提交数据
查看生成的文件:View-ToolWindows-Device File Explorer,进入
/data/data/com.example.myapplication.sharedpreferencestest/shared_prefs/目录下可查看到生成的data.xml文件
2.从sharedPreferences中读取数据
(1)创建SharedPreferences对象
(2)调用SharedPreferences对象的getString()等方法取出数据
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = findViewById(R.id.button);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取SharedPreferences对象
SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);
//获取SharedPreferences中存储的数据
String name = pref.getString("name", "");
int age = pref.getInt("age",0);
boolean married = pref.getBoolean("married", false);
//通过Log将获取的数据打印出来
Log.d("MainActivity","name is"+name);
Log.d("MainActivity","age is"+age);
Log.d("MainActivity","married is"+married);
}
});
}
方法解析:
getInt(String var1,int var2):取出int类型的数据。参数一为key值,参数二为默认值。即如果没有找到相应的值,则传入默认值
向SharedPreferences中存数据是SharedPreferences.Editor对象调用putInt()等方法
从SharedPreferences中取数据是SharedPreferences对象调用getInt()等方法
三、SQLite数据库存储
1.SQLite基本知识
SQLite是Android内置的轻量型数据库
数据库文件会存放在:/data/data//databases/数据库名
SQLite的数据类型:
integer:整型,real:浮点型,text:文本类型,blob:二进制类型
SQLiteOpenHelper:对数据库进行创建和升级的抽象类。
(1)抽象方法:
-
onCreate():创建数据库
-
onUpgrade():升级数据库
(2)构造方法:
SQLiteOpenHelper():
- 第一个参数:Context
- 第二个参数:数据库名
- 第三个参数:允许查询数据时返回一个自定义的Cursor,一般传入null
- 第四个参数:当前数据库的版本号,可用于对数据库升级
2.创建数据库
- getReadableDatabase():创建或打开一个现有的数据库(数据库不存在则创建,存在直接打开)。当数据库不可写入时,返回对象以只读方式打开数据库。
- getWritableDatabase():创建或打开一个现有的数据库(数据库不存在则创建,存在直接打开)。当数据库不可写入时,该方法报异常。
- execSQL(String sql):执行sql语句
(1)创建一个自定义类继承SQLiteOpenHelper抽象类,重写onCreate()和onUpgrade()
(2)创建SQL语句,并将sql语句定义成字符串常量
(3)在onCreate()方法中调用execSQL()方法执行sql语句
(4)创建自定义类的对象,指定数据库名和数据库版本号
(5)执行getWritableDatabase()方法创建数据库
public class MyDatabaseHelper extends SQLiteOpenHelper {
//创建SQL语句
public static final String CREATE_BOOK = "create table Book("
+"id integer primary key autoincreament,"
+"author text,"
+"price real,"
+"name text)";
private Context context;
public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//执行sql语句
db.execSQL(CREATE_BOOK);
Toast.makeText(context,"Created successed",Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
省略activity_main.xml的代码
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建MyDatabaseHelper对象。指定数据库名为Book.db
dbHelper = new MyDatabaseHelper(this,"Book.db",null,1);
Button createDatabase = findViewById(R.id.button);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//创建数据库
dbHelper.getWritableDatabase();
}
});
}
public SQLiteOpenHelper(Context context, String name,CursorFactory factory, int version)
- 第一个参数:上下文
- 第二个参数:数据库名
- 第四个参数:数据库版本号
3.升级数据库
想在数据库中再添加一个表
(1)在onCreate()方法里执行新的sql语句,并在onUpgrade()方法里删除已存在的表并调用onCreate()方法。
(2)将数据库版本指定为2
public class MyDatabaseHelper extends SQLiteOpenHelper {
//创建SQL语句
public static final String CREATE_BOOK = "create table Book("
+"id integer primary key autoincreament,"
+"author text,"
+"price real,"
+"name text)";
public static final String CREATE_CATEGORY = "create table Category("
+"id integer primary key autoincreament,"
+"category_name text)";
private Context context;
public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//执行sql语句建表
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(context,"Created successed",Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {//升级数据库
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
//重新创建表
onCreate(db);
}
}
修改MainActivity,将数据库版本改为2:
//指定数据库版本为2,表示对数据库进行了升级
dbHelper = new MyDatabaseHelper(this,"Book.db",null,2);
4、添加数据
SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法不仅可以用于创建和升级数据库,这两个方法还都会返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行CRUD操作了
(1)创建SQLiteDatabase对象
(2)创建ContentValues对象
(3)ContentValues对象调用put()方法组装数据到ContentValues中
(4)SQLiteDatabase对象调用insert()方法将ContentValues中的数据插入到表中
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"Book.db",null,2);
Button addData = findViewById(R.id.add);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取SQLiteDatabase对象
SQLiteDatabase db = dbHelper.getWritableDatabase();
//创建ContentValues对象用于存储要添加到表中的数据
ContentValues values = new ContentValues();
//组装第一条数据到ContentValues对象
values.put("name","Android");
values.put("author","Tom");
values.put("price",32.00);
//向数据库的Book表中插入第一条数据
db.insert("Book",null,values);
//清空ContentValues对象里存的值,以便存新数据
values.clear();
//组装第二条数据
values.put("name","Java");
values.put("author","Jack");
values.put("price",42.00);
//向数据库的Book表中插入第二条数据
db.insert("Book",null,values);
}
});
}
方法详解:
Contentvalues:是一种存储基本类型的数据的类,类似于HashMap<String,基本数据类型>这种形式。通过put()方法以键值对的方式存储数据。
insert(String table, String nullColumnHack, ContentValues values) :向表中添加数据
- 第一个参数:表名
- 第二个参数:在未指定添加数据的情况下给某些可为空的列自动赋值null
- 第三个参数:ContentValues对象
put(String key, String value):向ContentValues对象中添加数据。将表中每个列名及相对应待添加的数据传入即可。
clear():清空ContentValues中的数据
5、更新数据
(1)将更新数据组装到ContentValues对象里
(2)SQLiteDatabase调用update()方法
修改MainActivity中OnClick()中的代码为:
@Override
public void onClick(View view) {
//获取SQLiteDatabase对象
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
//将修改的数据组装到ContentValues对象中
values.put("price",30.00);
//修改Book表中name为Android的行
db.update("Book",values,"name=?",new String[]{"Android"});
}
方法详解:
update(String table, ContentValues values, String whereClause, String[] whereArgs):更新表中的数据
- 第一个参数:表名
- 第二个参数:ContentValues对象
- 第三个参数和第四个参数:用于约束更新某一行或某几行的数据。不指定默认更新所有行
6、删除数据
@Override
public void onClick(View view) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
//删除Book表中price>30的书
db.delete("Book","price>?",new String[]{"30.00"});
}
方法详解:
delete(String table, String whereClause, String[] whereArgs):删除表中的数据
第二、三个参数:用于约束删除某一行或某几行的数据。不指定默认更新所有行
7、查询数据
(1)创建SQLiteDatabase对象
(2)SQLiteDatabase对象调用query()方法查询到数据并返回Cursor对象
(3)遍历Cursor对象,
query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) :查询表中的数据。返回值为Cursor对象。
- 第一个参数:指定查询的表名
- 第二个参数:指定查询的列名
- 第三个参数:指定where的约束条件
- 第四个参数:where占位符具体值
- 第五个参数:指定需要group by的列
- 第六个参数:对group by后的结果进一步约束
- 第七个参数:指定查询结果的排序方式
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"Book.db",null,2);
Button queryData = findViewById(R.id.query);
queryData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
//查询表中的所有数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
//将数据指针移到第一行
if(cursor.moveToFirst()){
do{
//遍历Cursor对象,取出Cursor对象中的数据
String name = cursor.getString(cursor.getColumnIndex("name"));
/*cursor.getColumnIndex("author"):得到第一行author列的下标索引值,
*/
String author = cursor.getString(cursor.getColumnIndex("author"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
//打印数据到日志
Log.d("MainActivity","book name is"+"name");
Log.d("MainActivity","book author is"+"author");
Log.d("MainActivity","book price is"+"price");
}while(cursor.moveToNext());
}
//关闭游标
cursor.close();
}
原理:
先将查询出来的数据一行行存储到Cursor中,将光标定位到第一行。再调用Cursor的getColumnIndex()方法得到第一行每列的下标索引。调用Cursor的getString()、getDouble()、getInt()等方法取出第一行指定下标对应的值。将光标依次后移,取出每行的值。
方法详解:
Cursor:Cursor是数据库中每行的值。query()方法查询到的所有数据都会放到Cursor对象里。
Cursor的方法:
- getColumnIndex(String var1):获取到某一列在表中对应的位置索引
- getCount():返回Cursor 中的行数
- moveToFirst():移动光标到第一行,返回值为boolean
- moveToLast():移动光标到最后一行
- moveToNext():移动光标到下一行
- moveToPosition(int position):移动光标到一个绝对的位置
- getString(int columnIndex)、getInt(int columnIndex)、getDouble(int columnIndex):返回当前行指定列的值
8.使用SQL语句操作数据库
添加数据:
db.execSQL(“insert into Book(name,author,price) values (?,?,?,?)”,new String[]{“Android”,“Jack”,“27.00”});
更新数据:
db.execSQL(“update Book set price = ? where name = ?”,new String[]{“25.00”,“Android”});
删除数据:
db.execSQL(“delete from Book where price >?”,new String[]{“30”});
查询数据:
db.rawQuery(“select * from Book”,null);
除了查询数据使用SQLiteDatabase的rawQuery()方法,其他都使用execSQL()
四、LitePal操作数据库
1.LitePal简介
开源的Android数据库框架,采用对象关系映射的模式。不用编写一行SQL语句就能完成建表和增删改查操作。
2.配置LitePal
(1)在app/build.gradle文件的dependencies闭包中添加:
implementation 'org.litepal.android:java:3.0.0’
(2)配置litePal.xml文件
在main目录下创建assets目录,在该目录下新建litePal.xml文件。文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="BookStore"></dbname>
<version value="1"></version>
<list>
<mapping class="com.example.myapplication.Book"></mapping>
</list>
</litepal>
<dbname>
:用于指定数据库名
<version>
:用于指定数据库版本号
<list>
:用于指定所有的映射模型
<mapping>
:声明要配置的映射模型类
(3)AndroidManifest.xml标签中配置litepal
在application标签中加 android:name="org.litepal.LitePalApplication"
<application
android:name="org.litepal.LitePalApplication"
android:allowBackup="true"
...
</application>
3.创建和升级数据库
创建数据库:
(1)创建实体类,该类对应数据库中的表。并将该类添加到映射模型列表中
public class Book {
private int id;
private String name;
private String author;
private Double price;
//getter、setter方法省略
}
该Book类对应数据库中的Book表。记得要将该类添加到映射模型列表中(list标签中)
(2)Connector调用getDatabase()方法创建数据库
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button createDatabase = (Button)findViewById(R.id.create_dataBase);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//创建数据库
Connector.getDatabase();
}
});
}
方法详解:
getDatabase():创建数据库
升级数据库:
修改要改的内容,将数据库版本号加1
向Book表中添加一个press列,并在BookStore数据库添加新表Category
public class Book {
private String press;
//省略getter、setter方法
}
public class Category {
private int id;
private String categoryName;
private int categoryCode;
//getter、setter方法省略
}
在litepal.xml中将版本号加1,并在list中添加新的模型类
<litepal>
<dbname value="BookStore"></dbname>
<version value="2"></version>
<list>
<mapping class="com.example.myapplication.Book"></mapping>
<mapping class="com.example.myapplication.Category"></mapping>
</list>
</litepal>
4.添加数据
LitePal进行增删改查操作必须模型类必须继承LitePalSupport类。(DataSupport类已被弃用)
public class Book extends LitePalSupport{
...
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
Button addData = (Button)findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Book book = new Book();
//调用set()对Book中的值进行设置
book.setName("Android");
book.setAuthor("Jack");
book.setPrice(30.00);
book.setPress("Unknow");
book.save();
}
});
}
save():保存对表的修改
5.修改数据
方法一:
修改onClick()中的代码如下:
public void onClick(View view) {
Book book = new Book();
book.setName("Android");
book.setAuthor("Jack");
book.setPrice(30.00);
book.save();
//设置更新价格为20
book.setPrice(20.00);
book.save();
}
方法二(常用):
public void onClick(View view) {
Book book = new Book();
//更新的数据
book.setPress("MingRi");
//更新
book.updateAll("name=? and author=?","Android","Jack");
}
updateAll(String… conditions):修改表中的数据。参数为约束条件。若不指定约束条件表示修改所有数据。
setToDefault(String fieldName):设置字段为默认值。参数为字段名
6.删除数据
方法一:直接调用已存储对象的delete()方法
delete():删除表中数据
方法二(常用):调用LitePal的deleteAll()方法
public void onClick(View view) {
LitePal.deleteAll(Book.class,"price<?","20.00");
}
deleteAll(Class<?> modelClass, String… conditions):删除表中的数据。
- 第一个参数:指定删除哪张表中的数据。
- 第二个参数:约束条件。若未指定约束条件,表示删除表中所有数据。
更新和删除数据的方法一只能对已存储对象进行操作,限制较大。
已存储对象:调用过save()方法的对象
7.查询数据
public void onClick(View view) {
List<Book> books = LitePal.findAll(Book.class);
for(Book book:books){
Log.d("MainActivity","book name is"+book.getName());
Log.d("MainActivity","book author is"+book.getAuthor());
Log.d("MainActivity","book price is"+book.getPrice());
Log.d("MainActivity","book press is"+book.getPress());
}
findAll(Class modelClass, long… ids):查询表中的数据,返回值是Book类型的list集合。参数是表名
其他查询方法:
findFirst(Class modelClass) :查询表中的第一条数据
Book firstBook = DataSupport.findFirst(Book.class);
findLast(Class modelClass):查询表中的最后一条数据
Book lastBook = DataSupport.findLast(Book.class);
select(String… columns):指定查询哪几列的数据
List<Book> books = DataSupport.select("name","author").find(Book.class);
where(String… conditions):指定查询的约束条件
List<Book> book = DataSupport.where("price>?","30").find(Book.class);
order(String column):指定结果的排序方式
将查询的结果按书价从高到低排序:
List<Book> book = DataSupport.order("price desc").find(Book.class);
limit(int value):指定查询结果的数量
只查表中前三条数据:
List<Book> book = DataSupport.limit(3).find(Book.class);
offset(int value):指定查询结果的偏移量
查询表中第2、3、4条数据:
List<Book> book = DataSupport.limit(3).offset(1).find(Book.class);
查询Book表中第5-7行满足price>20的name、author、price这3列数据,并将结果按照页数升序排列:
List<Book> books = DataSupport.select("name","author","price")
.where("price>?","20.00")
.order("price")
.limit(3).offset(4)
.find(Book.class);