您的位置:首页 > 移动开发 > Android开发

Android开发基础知识整理之数据存储

2017-01-17 11:57 477 查看
本篇主要涉及Android中的数据持久化技术。

一、 文件存储

不对存储内容进行任何格式化处理,原封不动的保存到文件中。适合存储一些简单的文本数据或二进制数据。

(一) 存储

1. 获取FileOutputStream对象:使用Context类中的
openFileOutput()
方法,接收两个参数:(文件名, 操作模式)。

文件默认存储到
/data/data/<package name>/files/
目录下;

两种操作模式可选:MODE_PRIVATE(默认)和MODE_APPEND 。

2. 构建出OutputStreamWriter对象,再借此构建出BufferedWriter对象,调用它的
write
方法将数据写入文件。

public void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null;
try {
out =openFileOutput("data", Context.MODE_PRIVATE); // 获取FileOutputStream对象
writer = new BufferedWriter(new OutputStreamWriter(out); // 构建BufferedWriter对象
writer.write(inputText);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close()
}
} catch (IOException e) {
e.printStackTrace();
}
}
}


(二) 读取

1. 获取FileInputStream对象:使用Context类中的
openFileInput(文件名)
方法。

2. 构建出InputStreamReader,再借此构建出BufferedReader对象,读取到StringBuilder中,最后返回。

public String load() {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("data"); // 获取FileInputStream对象
reader = new BufferedReader(new InputStreamReader(in)); // 构建BufferedReader对象
String line = "";
while ((line = reader.readLine()) != null) {
content.append(line); // 逐行读取,若内容不为空添加到StringBuilder中
}
} catch (IOException e) {
e.printStackTrace;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return content.toString();
}


二、 SharedPreference存储

采用键值对的方式存储数据,支持多种不同的数据类型存储,使用XML格式来管理数据的。

(一) 存储

1. 获取SharedPreferences对象,有三种方法:

Context类中的
getSharePregerences(文件名, 操作模式)
方法。

SharedPregerences文件都存放在
/data/data/<package name>/shared_prefs/
目录下

操作模式只有MODE_PRIVATE可选,和传入0效果一样

Activity类中的
getPreferences(操作模式)
方法。

只接受一个操作模式参数,自动将当前活动类名作为文件名

PreferenceManager类中的
getDeafaultSharedPreferences(context)
方法。

是一个静态方法,接收一个context参数,使用当前应用程序包名作为前缀来命名文件

2. 向SharedPreferences文件中存储数据

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

(2) 向Editor对象中添加数据,根据数据类型调用
putString()
putBoolean()
等方法;

(3) 调用
apply()
方法提交数据。

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


(二) 读取

使用
getSring()
getBoolean()
等方法,接收两个参数:(键, 默认值)。

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


三、 SQLite数据库存储

适合存储大量复杂的关系型数据。

(一) 创建数据库

借助抽象类SQLiteOpenHelper,继承此类后重写
onCreate()
onUpgrade()
方法来创建和升级数据库。

SQLiteOpenHelper的构造方法接收4个参数:(Context, 数据库名, null, 版本号)。第三个参数允许在查询数据时返回一个自定义Cursor,一般传入null。

两个实例方法
getReadableDatabase()
getWritableDatabase()
用于创建或打开现有数据库,并返回一个可进行读写操作的对象。

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

public class MyDatabaseOpenHelper extends SQLiteOpenHelper {

public static final String CREATE_BOOK = "create table BOOK ("
+ "id integer primary key antoincrement, " // 设置为主键,自增长
+ "author text" // text表示文本类型
+ "price real, " // real表示浮点型
+ "pages integer, " // integer表示整型
+ "name text)";

private Context mContext;

public MyDataBaseHelper(Context context, String name, SQLiteDatabase.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) {
}

}


public class MainActivity extends AppCompatActivity {

private MyDatabaseHelper dbHelper;

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

}


(二) 升级数据库

1. 将建表语句添加到MyDatabaseHelper中;

2.
onUpgrade()
中执行DROP语句,再调用
onCreate()
方法重新创建;

3. 修改MainActivity中构造方法的版本号,使
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);
}


(三) 添加数据

使用SQLiteDatabase的
insert()
方法,接收三个参数:(要添加数据的表名, null, ContentValues对象)

第二个参数用于在未指定数据的情况下给某些为空的列自动赋值NULL,一般用不到直接传入null;

第三个参数的ContentValues对象提供一系列
put()
方法重载用于向其中添加数据,传入 (列名, 待添加数据) 即可。

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();
// 开始组装第二条数据
...
db.insert("Book", null, valuse); // 插入第二条数据


(四) 更新数据

使用
update()
方法,接收四个参数:(表名, ContentValues对象, 约束语句, 字符串数组)。

第二个参数中把要更新的数据组装进来;

第三个参数用于约束更新某一行或某几行的数据,对应SQL语句的where部分,包含占位符,例如”name = ?”;

第四个参数用一个字符串数组指定占位符的内容,如
new String[] {"The Da Vinci Code"}


SQLiteDatabase db = dbHelper.getWritaberDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
db.update("Book", values, "name = ?", new String[] {"The Da Vinci Code"}); // 更新书名为"The Da Vinci Code"的数据


(五) 删除数据

使用
delete()
方法,接收三个参数:(表名, 约束语句, 字符串数组)。

和insert类似,第二三个参数用于约束删除某一行或某几行数据。

db.delete("Book", "pages > ?", new String[] {"500"}); // 删除页数超过500的书


(六) 查询数据

1. 使用
query()
方法,最短的方法重载接收七个参数;

2. 查询完得到一个Cursor对象,调用
moveToFirst()
将数据指针移动到第一行位置(返回True表示移动成功数据不为空);

3. 通过一个循环遍历查询到的每一行数据,循环中可以通过Cursor的
getColumnIndex()
方法获取到某一列在表中对应的位置索引,将其传入对应取值方法中就可以读取到数据了;

4. 最后调用
colse()
方法关闭Cursor。

query()方法参数对应SQL部分描述
tablefrom table_name指定查询的表名
columnsselect column1, column2指定查询的列名
selectionwhere column = value指定where的约束条件
selectionArgs-为where中的占位符提供具体值
groupBygroup by column指定需要group by的列
havinghaving column = value对group by后的结果进一步约束
orderByorder by column1,column2指定查询结果的排序方式
// 查询Book表中的所有数据
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"));
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();


(七) 使用SQL操作数据库

添加数据

db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",
new String[] {"The Da Vinci Code", "Dan Brown", "454", "16.96"});


更新数据

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


删除数据

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


查询数据

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


四、 使用LitePal操作数据库

LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,并对常用数据库功能进行了封装。

(一) 配置LitePal

在app/build.grale文件中声明开源库的引用:

compile 'org.litepal.android:core:1.4.1'


配置litepal.xml。在app/src/main下创建一个assets目录,在其中创建一个litepal.xml文件,编辑其中内容:

<?xml version = "1.0" encoding="utf-8"?>
<litepal>
<!-- 数据库名 -->
<dbname value="BookStore" ></dbname>

<!-- 数据库版本号 -->
<version value="1" ></version>

<!-- 指定所有映射模型 -->
<list>
</list>
</litepal>


AndroidManifest中配置LitePalApplication。

<application
android:name="org.litepal.LitePalApplication"
...>
...
</application>


(二) 创建和升级数据库

1.创建数据库

(1) 根据要创建的表定义一个类,定义相应字段并生成对应的getter和setter方法;

(2) 将创建的类添加到映射模型列表中,使用
<mapping>
标签;

(3) 调用
Connector.getDatabase()
创建数据库。

/** 根据Book表的内容定义Book类 */
public class Book{

private int id;
private String author;
private double price;
private int pages;
private String name;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

... //生成各个字段对应的getter和setter方法

}


<!-- 添加到映射模型列表中 -->
<list>
<mapping class="com.example.litepaltest.Book"></mapping>
</list>


@Override
public void onClick(View v) {
Connector.getDatabase(); // 创建数据库
}


2. 升级数据库

更改想要修改的任何内容,然后将版本号加1即可。升级会保留之前表中的所有数据。

(三) 添加数据

创建出模型实例(要进行CRUD操作模型类必须继承字DataSupport类),调用set方法将所有要存储的数据设置好,最后调用
save()
方法即可。

public class Book extends DataSupport {
...
}


Book book = new Book();
book.setName("The Da Vinci Code");
book.setAuthor("Dan Brown");
book.setPages(454);
book.setPrice(16.96);
book.setPress("UnKnow");
book.save():


(四) 更新数据

new出模型实例,调用set方法设置要更新的数据,最后调用
updateAll()
方法执行更新操作(updateAll中可以指定约束条件)。

注意:要更新为默认值,使用
setToDefault()
方法。

/** 将书名为The Lost Symbol并且作者是Dan Brown的书价格更新为14.95,出版社更新为Anchor */
Bool book = new Book();
book.setPrice(14.95);
book.setPress("Anchor");
book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan Brown");


/** 将所有书页更新为0(默认值) */
Book book = new book;
book.setToDefault("pages");
book.updateAll();


(五) 删除数据

调用已存储对象(调用过save方法或通过LitePal提供的查询API查出来的对象)的
delete()
方法。

调用
DataSupport.deleteAll()
方法,接收三个参数:(要删除数据的表名, 约束条件, 占位符内容)

/** 删除Book表中价格低于15的书 */
DataSupport.deleteAll(Book.class, "price < ?", "15");


(六) 查询数据

调用
findAll()
方法,返回值为对应类型的List集合。

List<Book> books = DataSupport.finAll(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 pages is " + book.getPages());
Log.d("MainActivity", "book price is " + book.getPrice());
Log.d("MainActivity", "book press is " + book.getPress());
}


findFirst()
findLast()
分别查询第一条和最后一条数据.

通过连缀查询定制更多查询功能:

方法对应SQL部分描述
select()select指定查询哪几列数据
where()where指定查询的约束条件
order()order by指定结果的排序方式(desc降序,asc或不写为升序)
limit()limit指定查询结果的数量
offset()limit指定查询结果的偏移量
/** 查询Book表中第11~20条页数大于400的name、author、pages这三列数据,并将结果按页数升序排列 */
List<Book> books = DataSupport.select("name", "author", "pages")
.where("pages > ?", "400")
.order("pages")      // 默认为asc升序
.limit(10)           // 只查前10条
.offset(10)          // 偏移10个位置
.find(Book.class);


也支持使用原生SQL进行查询:调用
DataSupport.findBySQL(SQL语句, 占位符的值)
,返回一个Cursor对象。

Cursor c = DataSupport.findBySQL("select * from Book where pages > ? and price < ?", "400", "20");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息