《第一行代码》数据存储

11、数据存储

将数据存储到文件中

openFileOutput ()方法,可以用于将数据存储到指定的文件中。

这个方法接收两个参数,第一个参数是文件名,在文件创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data/<packagename>/files/ 目 录 下 的 。 

        第 二 个 参 数 是 文 件 的 操 作 模 式 , 主 要 有 两 种 模 式 可 选 ,MODE_PRIVATE 和 MODE_APPEND

        MODE_PRIVATE 是默认的操作模式,

表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容,

        MODE_APPEND 

则表示如果该文件已存在就往文件里面追加内容,不存在就创建新文件。

public void save() {
		String data = "Data to save";
		FileOutputStream out = null;
		BufferedWriter writer = null;
		try {
			out = 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();
			}
		}
	}

从文件中读取数据

openFileOutput()只接收一个参数,即要读取的文件名,然后系统会自动到/data/data/<package name>/files/目录下去加载这个文件,并返回一个FileInputStream 对象,得到了这个对象之后再通过 Java 流的方式就可以将数据读取出来了。

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

【SharedPreferences 存储】

使用键值对的方式来存储数据

获取到SharedPreferences对象

三种方式:

1、Context 类中的 getSharedPreferences()方法

此方法接收两个参数,第一个参数用于指定 SharedPreferences 文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences 文件都是存放在/data/data/<packagename>/shared_prefs/目录下的。

第二个参数用于指定操作模式,主要有两种模式可以选择,MODE_PRIVATE 和 MODE_MULTI_PROCESS。

MODE_PRIVATE 仍然是默认的操作模式,和直接传入 0 效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写。

MODE_MULTI_PROCESS 则一般是用于会有多个进程中对同一个 SharedPreferences 文件进行读写的情况。

2、Activity 类中的 getPreferences()方法

这个方法和 Context 中的 getSharedPreferences()方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为 SharedPreferences 的文件名。

3、PreferenceManager 类中的 getDefaultSharedPreferences()方法

这是一个静态方法,它接收一个 Context 参数,并自动使用当前应用程序的包名作为前缀来命名 SharedPreferences 文件。

向 SharedPreferences 文件中存储数据了,

主要可以分为三步实现:

1. 调用 SharedPreferences 对象的 edit()方法来获取一个 SharedPreferences.Editor 对象。

2. 向 SharedPreferences.Editor 对象中添加数据,

比如添加一个布尔型数据就使用putBoolean 方法,添加一个字符串则使用 putString()方法,以此类推。

3. 调用 commit()方法将添加的数据提交,从而完成数据存储操作

SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
	editor.putString("name", "Tom");
	editor.putInt("age", 28);
	editor.putBoolean("married", false);
	editor.commit();

生成了一个 data.xml文件

从SharedPreferences 中读取数据

SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
	String name = pref.getString("name", "");
	int age = pref.getInt("age", 0);
	boolean married = pref.getBoolean("married", false);

【SQLite 数据库存储】

Android 系统内置了数据库的!

SQLite 是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百 K 的内存就足够了,因而特别适合在移动设备上使用。

SQLite不仅支持标准的 SQL 语法,还遵循了数据库的 ACID 事务

创建数据库

integer 表示整型,real 表示浮点型,text 表示文本类型,blob 表示二进制类型

SQLiteOpenHelper 帮助类,借助这个类就可以非常简单地对数据库进行创建和升级

SQLiteOpenHelper 是一个抽象类,SQLiteOpenHelper 中有两个抽象方法,分别是onCreate()和 onUpgrade()

SQLiteOpenHelper 中 还 有 两 个 非 常 重 要 的 实 例 方 法 , getReadableDatabase() 和getWritableDatabase()。

这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。

不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而 getWritableDatabase()方法则将出现异常

构造方法中接收四个参数,

第一个参数是 Context,这个没什么好说的,必须要有它才能对数据库进行操作。

第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。

第三个参数允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null。

第 四 个 参 数 表 示 当 前 数 据 库 的 版 本 号 , 可 用 于 对 数 据 库 进 行 升 级 操 作 。

数据库文件会存放在/data/data/<package name>/databases/目录下

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 mContext;
		
		public MyDatabaseHelper(Context context, String name, CursorFactory	factory, int version) {
			super(context, name, factory, version);
			mContext = context;
		}
		
		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(CREATE_BOOK);
			Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
		}
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		}
	}

//MainActivity:

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

 

输入 adb shell,就会进入到设备的控制台,使用 cd 命令进行到/data/data/com.example.databasetest/databases/目录下,并使用 ls 命令查看到该目录里的文件

打开数据库:

sqlite3 数据库全名(sqlite3 Book.db)

查看数据库表:

键入.table 命令

查看建表语句

.schema

退出数据库的编辑

键入.exit 或.quit

升级数据库

1、

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		//这种方式会让老用户数据丢失
		db.execSQL("drop table if exists Book");
		db.execSQL("drop table if exists Category");
		
		//增加版本号判断
		switch (oldVersion) {
			case 1:
				db.execSQL(CREATE_CATEGORY);
			case 2:
				db.execSQL("alter table Book add column category_id integer");
			default:
		}
		
		onCreate(db);
	}	
	

 

细节:

switch 中每一个 case 的最后都是没有使用 break 的,为什么要这么做呢?这是为了保证在跨版本升级的时候,每一次的数据库修改都能被全部执行到

2、让 onUpgrade()方法执行

还记得 SQLiteOpenHelper 的构造方法里接收的第四个参数吗?它表示当前数据库的版本号,之前我们传入的是 1,现在只要传入一个比 1 大的数,就可以让 onUpgrade()方法得到执行了

添加数据:

SQLiteDatabase db = dbHelper.getWritableDatabase();
	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);
	db.insert("Book", null, values); // 插入第一条数据
	values.clear();
	
	// 开始组装第二条数据
	values.put("name", "The Lost Symbol");
	values.put("author", "Dan Brown");
	values.put("pages", 510);
	values.put("price", 19.95);
	db.insert("Book", null, values); // 插入第二条数据
	
	
	或:
	db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",
		new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" });

  

更新数据:

ContentValues values = new ContentValues();
	values.put("price", 10.99);
	db.update("Book", values, "name = ?", new String[] { "The DaVinci Code" });
	
	db.execSQL("update Book set price = ? where name = ?", new String[] { "10.99",
		"The Da Vinci Code" });

 

删除数据:

SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[] { "500" });

或
db.execSQL("delete from Book where pages > ?", new String[] { "500" });	

 

查询数据:

query()方法用于对数据进行查询。

 

   

这个方法的参数非常复杂,最短的一个方法重载也需要传入七个参数。

第一个参数不用说,当然还是表名,表示我们希望从哪张表中查询数据。

第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。

第三、第四个参数用于去约束查询某一行或某几行的数据,不指定则默认是查询所有行的数据。

第五个参数用于指定需要去 group by 的列,不指定则表示不对查询结果进行 group by 操作。

第六个参数用于对 group by 之后的数据进行进一步的过滤,不指定则表示不进行过滤。

第七个参数用于指定查询结果的排序方式,不指定则表示使用默认的排序方式。

SQLiteDatabase db = dbHelper.getWritableDatabase();
	Cursor cursor = db.query("Book", null, null, null, null, null, null);
	if (cursor.moveToFirst()) {
		do {
			// 遍历Cursor对象,取出数据并打印
			String name = cursor.getString(cursor.getColumnIndex("name"));
			String author = cursor.getString(cursor.getColumnIndex("author"));
			int pages = cursor.getInt(cursor.getColumnIndex("pages"));
			double price = cursor.getDouble(cursor.getColumnIndex("price"));
			
		} while (cursor.moveToNext());
	}
	cursor.close();

   

db.rawQuery("select * from Book", null);

可以看到,除了查询数据的时候调用的是 SQLiteDatabase 的 rawQuery()方法,其他的操作都是调用的 execSQL()方法。

事务:

SQLiteDatabase db = dbHelper.getWritableDatabase();
	db.beginTransaction(); // 开启事务
	
	try {
		db.delete("Book", null, null);
		if (true) {
			// 在这里手动抛出一个异常,让事务失败
			throw new NullPointerException();
		}
		ContentValues values = new ContentValues();
		values.put("name", "Game of Thrones");
		values.put("author", "George Martin");
		values.put("pages", 720);
		values.put("price", 20.85);
		db.insert("Book", null, values);
		
		db.setTransactionSuccessful(); // 事务已经执行成功
		
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		db.endTransaction(); // 结束事务
	}
	}
	

 

。。

猜你喜欢

转载自uule.iteye.com/blog/2419614