数据存储

数据存储

Android中的数据存储有5种

  • 文件存储
  • SharedPreferences
  • SQLite数据库
  • ContentProvider

数据存储方式

  • 文件存储:Android提供了openFileInput()和openFileOutput()方法来读取设备上的文件,其读取方式与Java中 I/O 程序时一样的。
  • SharedPreferences:这是Android提供的用来存储一些 “简单的配置信息的一种机制”,它采用了XML的格式将数据存储到设备中。
  • SQLite数据库:SQLite是数据库 “自带的一个 轻量级的数据库”,(它运算速度快,占用资源少,还支持SQL语法),一般使用它作为复杂数据的存储引擎。
  • ContentProvider:Android的四大组件之一,主要用于 “应用程序之间的数据切换”,可以将自己的数据共享给其它应用程序使用。
  • 网络存储:将数据库存储到 “服务器上”,通过网络提供的存储空间来存储/获取信息。

1.文件存储

文件存储是Android中最基础的一种储存方式,与Java中的文件存储类似,都是通过I/O流的形式把数据直接存储到文件中。

文件存储分为两类

  • 内部存储
  • 外部存储

1.内部存储

将应用程序中的数据以文件的形式存储到应用中(该文件默认位于data/data/<packagename>/目录下),此时存储的文件会被其所在的应用程序私有化,如果其它应用程序想要操作本应用程序中的文件,则需要设置权限。当创建的应用程序被卸载时,其内部存储文件也随之被删除。

Android程序有着自己的一套安全模型,默认情况下任何应用程序的文件都是私有的,其它程序无法访问。

Android开发中,内部存储使用的是Context提供的

  • openFileOutput()方法
  • openFileInput()方法

这两个方法能够返回进行读写操作的

  • FileOutputStream对象
  • FileInputStream对象

openFileOutput()方法:打开应用中对应的”输出流“,将数据存储到指定的文件中

FileOutputStream fos = openFileOutput(String name,int mode);

openFileInput()方法:打开应用中对应的”输入流“,读取指定文件中的数据

FileInputStream fis = openFileInput(String name);
  • name:表示文件名

  • mode:表示文件的操作模式,也就是读写文件的方式

    mode的取值有四种

    • MODE_PRIVATE:该文件只能被当前程序读写
    • MODE_APPEND:该文件的内容可以追加
    • MODE_WORLD_READABLE:该文件的内容可以被其它程序读
    • MODE_WORLD_WRITEABLE:该文件的内容可以被其它程序写
(1)存储数据

FileOutputStream对象可以将数据存储到文件中。

String fileName = "data.txt";	//文件名称
String content = "helloworld";	//要写入的数据
FileOutputStream fos = null;

	try{
    	fos = openFileOutput(fileName,MODE_PRIVATE);	//通过openFileOutput()方法返回FileOutputStream对象
    	fos.write(content.getBytes());	//通过FileOutputStream对象fos的write()方法将数据写入“data.txt”文件中
	}catch(Exception e){
    	e.printStackTrace();
	}finally{
    	try{
        	if(fos!=null){
            	fos.close();	//关闭输出流
        	}
    	}catch(IOException e){
        	e.printStackTrace();
    	}
	}
(2)读取数据

FileInputStream对象能够读取内部存储中的数据

String content = "";
FileInputStream fis = null;

	try{
    	fis = openFileInput("data.txt");	//获取文件输入流对象
    	byte[] buffer = new byte[fis.available()];	//创建缓冲区:通过available()获取文件长度,并创建相应大小的byte数据作为缓冲区
    	fis.read(buffer);					//通过read()方法,将文件内容读取到buffer缓冲区
    	content = new String(buffer);		//将读到的内容转换成指定字符串
	}catch(Exception e){
   		e.printStackTrace();
	}finally{
   	 	try{
      	  if(fis!=null){
         	fis.close();	//关闭输入流
          }
    	}catch(IOException e){
        	e.printStackTrace();
    	}
	}

2.外部存储

​ 将数据以文件的形式存储到一些外部设备上(SD卡,或设备内嵌的存储卡),属于永久性的存储方法(外部存储的文件通常位于mnt/sdcard目录下,不同的厂商生产的手机可能不同)。外部存储的文件可以被其它应用程序共享。

(1)存储数据
  • Environment.getExternalStroageState():确认外部设备是否可用(是否存在SD卡)

    当外部设备可用并且具有读写权限时,那么就可以通过FileInputStream 和 FileOutputStream对象来读写外部设备中的文件

  • getExternalStroageDirectory():获取SD卡目录(避免将路径写成固定值而找不到SD卡)

String state = Enviroment.getExternalStroageState();	//获取外部设备的状态

	if(state.equals(Enviroment.MEDIA_MOUNTED)){		//判断外部设备是否可用
  		File SDPath = Enviroment.getExternalStroageDirectory();	//获取SD卡目录
    
    	String file = new File(SDPath,"data.txt");
    	String data = "helloworld";
        FileOutputStream fos = null;
    	
        try{
        	fos = new FileOutputStream(file);	//创建文件输出流对象
        	fos.write(data.getBytes());			//将数据写入到文件中
    	}catch(Exception e){
        	e.printStackTrace();
    	}finally{
        	try{
            	if(fos!=null){
                	fos.close();
            	}
        	}catch(){
            	e.printStackTrace();
        	}
    	}
	}	
(2).读取数据
String state = Environment.getExternalStorageState();	//获取外部设备的状态

	if(state.equals(Enviroment.MEDIA_MOUNTED)){			//判断外部设备是否可用
		File SDPath = Enviroment.getRxternalStorageDirectory();	//获取SD卡目录
        
		File file = new File(SDPath,"data.txt");		//创建文件对象
		FileInputStream fis = null;		
		BufferedReader br = null;
		
        try{
			fis =new FileInputStream(file);		//创建文件输入流对象
			br = new BufferedReader(new InputStreamReader(fis));	//创建字符输入缓冲流的对象
			String data = br.readLine();		//读取数据
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(br!=null){
				try{
					br.close();			//关闭字符输入流
				}catch(IOException e){
					e.printStackTrace();
				}
			}
			if(fis!=null){
				try{
					fis.close();	//关闭输入流
				}catch(Exception e){
					e.printStaceTrace();
				}
			}
		}
	}

3.SharedPreferences存储

SharedPreferences是Android平台上一个轻量级的存储类,用于持久化存储一些少量数据(例如:用户名,密码……)

1.将数据存入SharedPreferences中

	//调用getSharedPreferences获取实例对象,
	//(该对象本身只能获取数据,不能对数据存储和修改)
	//data表示文件名,MODE_PRIVATE表示文件操作模式
SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);

	//获取编辑器,
	//通过调用SharedPreferences类的edit()方法获取可编辑的Editor对象
SharedPreferences.Editor editor = sp.edit();
		//通过Editor对象的putXXX()方法存储数据
	eidtor.putString("name","传智播客");	//存入String类型数据
	eidtor.putInt("age",8);				   //存入int类型数据
		//提交修改
	editor.commit();	
  • SharedPreferences中的Editor编辑器是通过key/value(键值对)的形式存储数据,并且根据数据类型的不同,调用不同的方法
  • 数据保存在 【data/data/<paceagename>/shared_prefs】文件夹下XML文件中,
  • 其中value值只能是float、int、long、boolean、String、Set<String>类型数据

2.读取与删除SharedPreferences中的数据

(1)读取数据
	//需要 获取 SharedPreferences对象
SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
	//使用对象的getXXX()方法根据相应的key值获取到value的值
String data = sp.getString("name","")

getString()方法中的参数

  • name:key值
  • 第2个参数:缺省值(如果找不到该key,)
(2)删除数据
//只需要 调用 Editor对象的remove(String key)方法或者clear()方法

	editor.remove("name");	//删除一条数据
	editor.clear();			//删除所有数据

??????????????????????????????????????????????????

保存SharedPreferences的key值时,可以用静态变量保存,以免存储、删除时写错

例如:private static final String key = "incast";

4.SQLite数据库存储

​ 用于存储程序中的”大量数据“,并对数据进行管理和维护

1.SQLite数据库的创建

创建一个类继承SQLiteOpenHelper类,在该类中重写onCreate()方法onUpgrade方法

	//继承SQLiteOpenHelper类
public class MyHelper extends SQLiteOpenHelper{		
    	//重写该类的构造方法
    	//调用父类SQLIteOpenHelper的构造方法(此时会创建一个名为“itcast.db”的数据库)
    public MyHpelper(Content content){		
        super(content,"itcast.db",null,2);	
    }	
    
   		//oncreat()方法,数据库第一次被创建时调用该方法(通常用于初始化表结构)
    public void onCreate(SQLiteDatabasre db){
       		 //初始化数据库的表结构,执行一条连接表的SQL语句(以创建一个information表为例)
        db.exeSQL("CREATE TABLE information(_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),price INTERGET)");
    }
   		//onUpgrade()方法,当数据库的版本号增加时调用(如果版本号不增加,则该方法不调用)
    public void onUpgrade(SQLitedDatabase db,int oldVersion,int newVersion){
        
    }
} 

父类SQLiteOpenHelper构造方法的参数

  • content:上下文对象
  • incast.db:数据库名称
  • null:游标工厂(通常是null)
  • 2:数据库的版本

2.SQLite数据库的基本操作

1.新增数据
public void insert(String name,String price){
    MyHelper helper = new MyHelper(MainActivity.this);
    	
    	//获取可读写SQLiteDatabase对象
    SQLiteDatabase db = helper.getWritableDatabase();	
   
    	//创建ContentValues对象
    	//将数据添加到ContentValues对象
    ContentValues values = new ContentValues();		
    values.put("name",name);	
    values.put("price",price);	
    
    	//insert()方法,插入一条数据到information表
    long id = db.insert("information",null,values);	
   		
    	//关闭数据库
    db.close();		
}

insert()方法中的参数

  • information:数据表的名称
  • null:如果发现将要插入的行为空行时,会将这个列名的值设置为null
  • vlaues:ContentValues对象

ContentValues类类似于Map类,通过键值对的形式存入数据,key表示插入数据的列名,values表示插入的数据

2.删除数据
public void delete(long id){
		//获取可读写SQLiteDatabase对象
    SQLiteDatabase db = helper.getWritableDatabase();
	
    	//delete()方法,从information表中删除对应的数据
    int number = db.delete("information","_id=?",new String[]{id+""});
    
    db.close();
    return number;	//返回删除的行数
}

删除数据时不需要使用ContentValue对象来添加参数,而是使用一个“字符串”和“字符串数组”来添加“参数名”和“参数值”

3.修改数据
public void update(String name,String price){
    SQLiteDatabase db = helper.getWritableDatabase();
   
    	//添加需要修改的“字段名”和“字段值”放到value对象中
    ContentValues values = new ContentValues();
    values.put("price",price);	
   	
   		//通过对象db调用update()方法来修改数据表中对应的数据
    int number = db.update("information",values,"name=?",new String[]{name});
    	
    db.close();
    return number;	//返回修改的行数
}

update()中的参数

  • information:数据库表
  • values:ContentValues对象(需要修改的最新的数据)
  • name=?:要修改的数据的查询条件
  • new String[]{name}:查找条件的参数
4.查询数据
public void find(int id){
    MyHelper helper = new MyHelper(MainActivity.this);
    	//获取可读SQLiteDatabase对象
    SQLiteDatabase db = helper.getReadableDatabase();	
   
    	//通过query()方法查询数据
    	//
    (返回的是一个行数集合Cursor,Cursor是一个游标接口,提供了遍历查询数据的方法)
    Cursor cursor = db.query("infomation",null,"_id=?",new String[]{id+""},null,null,null);
    
    	//通过getCount()方法获取到查询结果的总数
    	//判断cursor有多少个数据,如果没有就不要进入循环了
    if(cursor.getCount()!=0){	
        	//通过moveToNext()方法移动游标指向下一行数据
        while(cursor.moveToNext()){	
            	//通过getString()方法传入列名获取数据
            String _id = cursor.getString(Cursor.getColumnIndex("_id"));
            String name = cursor.getString(Cursor.getColumnIndex("name"));
            String price = cursor.getString(Cursor.getColumnIndex("price"));
        }
    }
    cursor.close();	//关闭游标
    db.close();
}

query()方法中的参数

  • information:数据表名称
  • null:查询的列名
  • _id=?:接收查询条件的子句
  • new String[]{id+" "}:接受查询子句对应的条件值
  • null:分组方式
  • null:接受having条件(即定义组的过滤器)
  • null:排序方式

??????????????????????????????????????????????????

通过SQL语句进行数据库的操作

还可以通过exeSQL()方法通过SQL语句对数据库尽心操作

  • 增加一条数据
db.exeSQL("insert into information (name,price) values(?,?)",new Object[]{name,price});
  • 删除一条数据
db.exeSQL("delete from information where _id=1");
  • 修改一条数据
db.exeSQL("update information set name=? where price=?");
  • 执行查询的SQL语句
Cursor cursor = db.rawQuery("select * from information where name=?",new Object[]{name,price});

查询操作使用的是rawQuery()方法,因为查询数据库会返回一个结果集Cursor,而exeSQL()方法没有返回值

3.SQLite数据库中的事务

ACID:数据库事务正确执行的四个基本要素的缩写

  • 原子性(Atomicity):表示事务是一个不可在分割的单位,事务中的操作要么全部成功,要么全部失败回滚
  • 一致性(Consistency):表示事务开始之前和结束之后,数据库的完整性没有被破坏(即数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性)
  • 隔离性(Isolation):表示并发的事务是相互隔离的。(即一个事务内部的操作必须封锁起来,不会被其它事务影响到)
  • 持久性(Durability):表示事务一旦提交后,该事务对数据做的更改便持久保存在数据库中,并不出现回滚

模拟银行转账功能

  • 张三取出1000元时,王五存入1000元
PersonSQLiteOpenHelper helper = new PersonSQLiteOpenHelper(getApplication());

//获取一个可读写的SQLiteDatabase对象
SQLiteDatabase db = helper.getWritableDatabase();
//开始数据库的事务
db.beginTransaction();
	try{
        //执行转出操作
        db.exeSQL("update person set account = account -1000 where name=?",new Object[]{"张三"});
        //执行转入操作
        db.exeSQL("update information set account = account +1000 where name=?",new Object[]{"王五"});
        //标记数据库事务执行成功
        db.setTransactionSuccessful();
    }catch(Exception e){
        Log.i("事务处理失败",e.toString());
    }finally{
        db.endTransaction();	//关闭事务
        db.close();		//关闭数据库
    }

事务操作完成后一定要使用endTransaction()方法关闭事务

当执行endTransaction()方法

  • 首先,会检查是否有事务执行成功的标记
    • 有,则提交数据
    • 无,则回滚数据
  • 最后,会关闭事务

如果不关闭事务,事务只有到超时才自动结束,会降低数据库并发效率,通常关闭事务的操作会在finally中执行

posted @ 2020-09-29 17:39  -清影-  阅读(299)  评论(0)    收藏  举报