《第6章 数据存储全方案——详解持久化技术》总结

  • 6.1持久化技术简介

保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,持久化技术提供了一种机制,可以让数据在瞬时状态和持久状态之间进行转换。
Android系统中主要提供了3种方式用于简单地实现数据持久化功能,即:文件存储SharedPreference存储数据库存储

  • 6.2 文件存储

文件存储是一种最基本的数据存储方式,不对存储的内容进行任何的格式化处理,所有数据都是直接保存到文件当中的,因而它比较适合用于存储一些简单的文本数据二进制数据
如果想要用文件存储一些较为复杂的文本数据,就需要定义一套自己的格式规范,这样可以方便之后将数据从文件中重新解析出来。

  • 6.2.1 将数据保存到文件中

Context类提供了一个openFileOutput()方法,用来将数据存储到指定的文件中。
它有两个参数,第一个参数是文件名(不包含路径).
第二个参数是文件的操作模式:MODE_PRIVATEMODE_APPEND
下面一段代码是将一段文本内容保存到文件中:

public void save(){
	String data = "data to save";
	FileOutputStream out = null;
	BufferedWriter writer = null;
	try{
		out = new openFileOutput("data",Context.MODE_PRIVATE);
		writer=new BufferedWriter(new OutputStreamWriter(out));
		writer.write(data);
		}catch(IOException e){
			e.printStackTrace();
			}finally{
				try{
					if(writer!=null){
						writer.close();
						}
					}catch(IOException e){
						e.printStackTrace();
						}
					}
}

然后在活动的onDestroy()方法中调用这个save函数,就会达到在程序销毁之前将输入的数据保存下来的目的

  • 6.2.2从文件中读取数据

将数据保存到文件中时,我们是调用的Context类的openFileOutput()方法。
从文件中读取数据时,我们要调用Context类中的openFileInput()方法。
这个方法只接受一个参数,即读取的文件名,然后就会去目录下加载这个文件,并返回一个FileOutputStream对象
以下是一个从文件中读取数据的代码示例:

public String load(){
	FileInputStream in = null;
	BufferedReader reader = null;
	StringBuilder content = new StringBuilder();
	try{
		in = Context.openFileInput("data");
		reader = new BufferedReader(New InputStreamReader(in));
		String line = "";
		while((line = reader.readLine())!=null)
			content.append(line);
		}
		catch(IOException e){
			e.printStackTrace();
			}
		finally{
			try{
				if(reader!=null)
					reader.close();
				}
				catch(IOException e)
				{	e.printStackTrace();}
				}
	return content.toString();
}			

TextUtils.isEmpty()方法可以判断一个String是不是空值的两种情况,即:null或空字符串,不需要单独判断这两种情况然后用逻辑运算符进行连接

  • 6.3SharedPreferences存储

SharedPreferences是用键值对的方式来存储的

  • 6.3.1将数据存储到SharedPreferences中

首先要获得SharedPreferences对象,有三种方法:

  1. Context类中的getSharedPreferences()方法
    1. 接收两个参数:第一个是SharedPreferences文件的名称,如果不存在会创建 一个。
    2. 第二个是操作模式,只有MODE_PRIVATE一种模式(是默认的操作模式, 和传入0的效果一样,表示只有当前的应用程序可以对这个SharedPreferences对象进行操作
  2. Activity类中的getPreferences()方法
    这个方法和Context类中的getSharedPreferences()方法很相似,不过只接受一个参数:操作模式。
    因为调用这个方法时,会自动地将当前活动的类名作为SharedPreferences文件的文件名
  3. PreferencesManager类中的getDefaultSharedPreferences()方法
    这是一个静态方法,接收一个Context参数,并自动使用当前的报名作为类名来命名SharedPreferences文件

得到了SharedPreferences对象之后,就可以向其中存储数据了,主要分为3步实现:

  1. 调用SharedPreferences对象的edit()方法,来获取一个SharedPreferences.Editor对象
  2. SharedPreferences.Editor对象中添加数据。比如添加一个布尔类型的数据用putBoolean()方法,添加一个字符串则用putString()方法
  3. 调用apply()方法,将添加的数据提交,从而完成数据存储操作。

  • 6.3.2 从SharedPreferences中读取数据

    对应于向SharedPreferences对象中存储数据时使用的putString,putBoolean(),putInt()等方法,读取数据时使用对应的get方法,如:getString(),getInt()。但这些方法都接收两个参数,第二个参数是传入的键找不到值时,返回的默认值
  • 6.3.3 实现记住密码的功能

    一个新的控件CheckBox,它的isChecked()方法可以判断该复选框是否被选中
    SharedPreferences.Editor对象的clear()方法,可以清除文件中的值。

使用SharedPreferences文件进行存储是非常不安全的,都是以明文存储的,真正应用时还要结合一定的加密算法来对密码进行保护

  • 6.4 SQLite数据库存储

  • 6.4.1 创建数据库

  • Android提供了一个SQLiteOpenHelper类,这是一个抽象类,需要实现其中的两个方法onCreate()onUpgrade()方法
  • 除此之外,类中还有两个非常重要的实例方法getReadableDatabase()getWritableDataBase()方法,这两个方法都可以创建一个数据库或者打开一个数据库(如果数据库已存在时直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。

  • 两个方法的不同之处:
  • 当数据库不可写入时(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式打开
  • getWritableDatabase则会出现异常

  • SQLiteOpenHelper中有两个构造函数可供重写,一般使用参数少一点的构造函数
    1. 第一个参数是Context,必须要有它才能对数据库进行操作
    2. 第二个参数是数据库名,创建数据库时使用的名称
    3. 第三个参数允许我们在查询数据的时候返回自定义的一个Cursor,一般都是传入null
    4. 第四个参数是当前数据库的版本号,可用于对数据库的升级操作

下面是创建一个Book表的建表语句:

create table Book(
id integer primary key autoincrement,
author text,
price real,
pages integer,
name text)

SQLite中的数据类型:

类型表示
整形integer
浮点型real
文本数据text
二进制blob
主键primary key
自增长autoincrement

下面是一个继承SQLiteOpenHelper类的实例:

public class MyDatabaseHelper extends SQLiteOpenHelper{
	public static final String CREATE_BOOK="create table Book("
		+"id integer primary key autoincrement,"
		+"author text,"
		+"price real,"
		+"pages integer,"
		+"name text)";
	private Context context;
	public MyDatabaseHelper(Context context,String name,SQLiteDatabase.CursorFactory cursor,int version){
		super(context,name,cursor,version);
		this.context=context;}
	@Override
	public void onCreate(SQLiteDatabase db){
		db.execSQL(CREATE_BOOK);
		Toast.makeText(context,"Create succeeded",Toast.LENGTH_SHORT).show();
	}
	
	@Override
	public void onUpgrade(SQLiteDatabase db,int oldversion,int new version){
		}
}

Activity中使用该类:

MyDatabaseHelper dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
	public void onClick(View v){
		dbHelper.getWritableDatabase();
	});

  • SQLite数据库的查看

  • 使用adb shell工具对数据库进行查看
  • adb是Android Studio中自带的一个调试工具,使用这个工具可以对连在电脑上的手机或者模拟器进行操作。它存放在sdk的platform-tools目录下,如果想在命令行里面使用,必须先把它配置到环境变量里面
  • 在环境变量里面的Path里面加入:
    C:\Users\35326\AppData\Local\Android\Sdk\platform-tools
    
  • 配置完成后,即可使用了:
  • 打开命令行界面,输入adb shell,如果命令行上显示的是$符号,说明现在的身份是普通用户。按su命令,进入到root模式。进入超级管理员身份后,命令提示符会变为#
  • 接下来cd到
/data/data/com.example.databasetest/databases/目录下
  • 然后使用ls命令会看到我们新创建的数据库BookStore.db,还会有一个BookStore.db-journal文件,这个文件是为了让数据库能够支持数据库事务而产生的临时日志文件,一般是0字节
  • 接下来要打开数据库,使用sqlite3 BookStore.db命令
  • 使用.table命令。能够看到目前数据库中有哪些表格。
  • 使用.schema命令,能够看到数据库中的建表语句。
  • 退出数据库使用.exit.quit命令
  • 退出adb s1hell使用exit命令

  • ##6.4.2升级数据库
  • 修改onUpgrade()方法如下:
@Override
public void onUpgrade(SQLiteDatabase db,int oldversion,int newversion){
	db.execSQL("drop table if exists Book");
	db.execSQL("drop table if exists Category");
	onCreate(db);
}
  • 修改onCreate()方法:
public void onCreate(SQLiteDatabase db,){
	db.execSQL(CREATE_BOOK);
	db.execSQL(CREATE_CATEGORY);
	Toast.makeText(context,"Create succeeded",Toast.LENGTH_SHORT).show();
}
  • 然后要修改得到数据库对象的代码,原先传入的版本号是1,修改为2或者更高的数字,这样onUpgrade()方法就会执行;
  • 如果传入的版本号比以前的版本号低,**那么会调用自定义类中的onDowngrade()方法,实现数据库的降级 **
  • 代码如下:
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);

  • ##6.4.7使用SQL操作数据库(数据库的增删改查)
  • SQLite数据库提供了一系列的增删改查方法,但是个人觉得太过于繁琐,不如直接用数据库语句进行操作,因此,专门提供的方法没有进行记忆
  • 增删改的方法都如下所示:安卓参考文档中不建议这样使用
db.execSQL("insert into Book(name,author,pages,price) values(?,?,?,?)",new String[]{"The Da Vinci Code","Dan Brown",
                "454","16.96"});
db.execSQL("insert into Book(name,author,pages,price) values(?,?,?,?)",new String[]{"The Lost Symbol","Dan Brown",
                "510","19.95"});


注意:

  1. SQLite类位于android.database.sqlite中,有两个execSQL()方法:
    1. public void execSQL(String sql)方法:
      文档中原文解释如下:
      Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
      It has no means to return any data(such as the number of affected rows).Istead,you're encouraged to use insert(),update(),等方法
      
      也就是说 不建议用这个方法执行SQL语句,只适合用来执行改变表结构的语句……还要回去使用那些复杂的其他的本类提供的方法……………………鸡肋鸡肋,食之无味,弃之可惜。
    2. public void execSql(String sql,Object[] bindArgs)也是类似的说法…………鸡肋鸡肋
  2. 关于接口Cursor
    1. 位于android.database中,(android.database.Cursor
    2. 这个对象可由数据库对象SQLiteDatabase的对象的rawQuery()方法得到
    3. 使用:
      • 有moveToFirst(),moveToNext(),moveToLast()等方法,返回值都是boolean类型


  • 6.5 使用LitePal操作数据库

关于LitePal数据库的所有用法都可以在链接:https://github.com/LitePalFramework/LitePal中找到

  1. 首先在app.gradle文件的dependencies闭包中加入一行依赖:implementation "org.liteoal.android:java:3.0.0"
  2. 然后在main文件夹下新建一个asset文件夹,里面新建一个litepal.xml文件,然后编辑该文件中的内容:
    <?xml version="1.0" encoding="utf-8"?>
    <litepal>
    <!--
    	Define the database name of your application.
    	By default each database name should be end with .db.
    	If you didn't name your database end with .db,
    	LitePal would plus the suffix automatically for you.
    	For example:
    	<dbname value="demo" />
    -->
    <dbname value="BookStore.db" />
    
    <!--
    	Define the version of your database. Each time you want
    	to upgrade your database, the version tag would helps.
    	Modify the models you defined in the mapping tag, and just
    	make the version value plus one, the upgrade of database
    	will be processed automatically without concern.
    		For example:
    	<version value="1" />
    -->
    <version value="2" />
    
    <!--
    	Define your models in the list with mapping tag, LitePal will
    	create tables for each mapping class. The supported fields
    	defined in models will be mapped into columns.
    	For example:
    	<list>
    		<mapping class="com.test.model.Reader" />
    		<mapping class="com.test.model.Magazine" />
    	</list>
    -->
    <list>
        <mapping class="com.example.litepaltest.Book"/>
        <mapping class="com.example.litepaltest.Category"/>
    </list>
    
    <!--
        Define where the .db file should be. "internal" means the .db file
        will be stored in the database folder of internal storage which no
        one can access. "external" means the .db file will be stored in the
        path to the directory on the primary external storage device where
        the application can place persistent files it owns which everyone
        can access. "internal" will act as default.
        For example:
        <storage value="external" />
    -->
    
    </litepal>
    
  3. AndroidManifest.xml中配置一下LitePalApplication
    <application>
    	android.name="org.litepal.LitePalApplication"
    </application>
    
    如果本来就有一个活动已经有了android.name参数,那么只需要在自己的活动的onCreate()方法中,调用静态方法LitePal.initiatlize(Context)方法
  4. 接下来创建实体类继承自LitePalSupport类,创建getter()setter()方法
  5. 调用LitePal.getDatabase()方法可以得到一个数据库
  6. :调用对象的save()方法
  7. 更新
    1. find()方法得到的对象去调用save()方法
    2. update(id)去更新特定的一行
    3. updataAll()去更新某些行
  8. 删除
    1. 调用LitePaldelete(class,id)方法去删除某一行
    2. 调用LitePaldeleteAll(class,...)方法去删除某些行
  9. 查询
    1. LitePal的一系列find()方法

LitePal项目地址:

https://github.com/LitePalFramework/LitePal

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值