自学安卓编程权威指南(十一)

这章主要是来学习SOLite数据库

对于,数据保存来说,有的需要持久化保存,那么此时临时性的savedInstanceState显然不能完成任务,那么此时还好安卓有提供一个沙盒目录,就是data/data/应用包名,把文件放在沙盒里面可以阻止其他应用对他的访问,但是保存大量数据的时候,不会使用txt这种格式的,原因是因为要度txt的话需要读取花费太多的时间,此时就需要用到SQLite数据库了

一.首先需要先定义schema(数据字段)

在创建数据库之前我们要先清楚知道我们要存储什么样的数据,创建schema的方式有很多,但是我们应该不要去重复造轮子,应该避免在应用中重复使用遵守的编程规则

这边先来简单的在Java代码中定义data schema(描述表名和数据字段)

首先先创建定义schema的Java类,将其命名为CrimeDbSchema,然后再新建类的对话框中输入包名 database.CrimeDbSchema。这样就可以把这份文件放入专用的包名中去,实现数据库的相关代码的统一组织和归类

 

(1)在CrimeDbSchema中定义一个数据表的内部类

public class CrimeDbSchema {

public static final class CrimeTable{

public static final String NAME = "crimes";

}

}

内部类的作用是定义数据表元素的String常量,

然后的内部类里面再定义一个类来存储数据表元素

public static final class Cols {

public static final String UUID = "uuid";

public static final String TITLE = "title";

public static final String DATE = "date";

public static final String SOLVED = "'solved";

}

有了这些代码就可以在Java代码中安全引用了

二.对于数据库来说,它有需要步骤需要判断,但是安卓已经为我们提供了一个SQLiteOpenHelper类来解决许多伪问题,我们应该新建一个类去继承这个类,然后覆盖父类的方法,如下面代码:

public class CrimeBaseHelper extends SQLiteOpenHelper {

private static final int VERSION = 1;

private static final String DATABASE_NAME = "crimeBase.db";

public CrimeBaseHelper(Context context){

super(context,DATABASE_NAME,null,VERSION);

}

public void onCreate(SQLiteDatabase db){

}

public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){

}

(2)然后我们就应该在之前的模型类中去创建和使用数据库

public class CrimeLab {

private Context mContext;

private SQLiteDatebase mDatabase;

private CrimeLab(Context context){

mContext = context.getApplicationContext();

mDatabase = new CrimeBaseHelper(mContext).getWritableDatabase();

mCrimes = new ArrayList();

 

}

}

使用getWritableDatabase()方法时,它会去完成创建数据库的各种逻辑,onCreate()时来创建数据库的,而onUpdate()方法是用来升级数据库的

下面得代码是用来创建SQL的,放在onCreate()代码中:

db.execSQL("create table" + CrimeDbSchema.CrimeTable.NAME);

接着在里面去创建数据表:

db.execSQL("create table" + CrimeDbSchema.CrimeTable.NAME + "(" + " _id integer primary key autoincrement," + CrimeTable.Cols.UUID + " ," + CrimeTable.Cols.TITLE + " ," + CrimeTable.Cols.DATE + " ," + CrimeTable.Cols.SOLVED + ")");

在创建数据表的时候记得需要把每一个元素之间添加逗号,不然创建数据表会失败,在表名的后面添加"(",然后再添加数据表元素

 

三.处理数据库的相关问题,当要升级数据库时,我们可以选择记录版本,然后再onUpgrade()中去升级,但是最好的方法就是直接删除数据库文件,然后再重新开始,这是在开发时的。

四.最后如果我们就要改用mDatabase来存储数据了,在原来的代码上删除与mCrime的代码,然后改用mDatabase来存储数据

而如果想要对数据库写入数据,那么就需要使用ContentValue类了,这个类就是用来用来写入和更新数据的,它是一个键值存储类,它只存储SQLite数据,

要将Crime记录转换成ContentValues,那么就是需要在CrimeLab中创建ContentValve实例,然后创建如下面的私有方法用来村粗数据,

private static ContentValues getContentValues(Crime crime) {

ContentValues values = new ContentValues();

values.put(CrimeTable.Cols.UUID,crime.getId().toString());

values.put(CrimeTable.Cols.TITLE,crime.getTitle());

values.put.(CrimeTable.Cols.DATE,crime.getDate());

values.put(CrimeTable.Cols.SOLVED,crime.isSolved()? 1 : 0);

return valves;

}

ContentValues的键创建的键就是数据表字段,不然会导致数据插入和更新失败,除了id由数据库自动创建外,其他的都需要代码来创建。

此时的添加一条数据就是等于,对数据库插入了一条数据,可以使用下面的代码:

public void addCrime(Crime c){

ContentValues values = getContentValues(c);

mDatabase.insert(CrimeTable.NAME,null,values);

}

第一个参数就是数据表名,第三个就是要写入的数据,第二个参数我们经常传入null

 

而如果想要用来更新列表,那么我们就是用下面的代码来

public void updateCrime(Crime crime){

String uuidString = crime.getId().toString();

ContentValues values = getContentValues(crime);

mDatebase.update(CrimeTable.NAME,values,CrimeTable.Cols.UUID + " = ?",new String[]{ uuidString});

}

 

对于这个方法来说,我们需要确认知道我们需要传入需要更新的记录,做法就是创建where子句,然后指定where子句的参数值,

最后当我们创建好数据表后,我们就需要在onPause()方法中去调用刷新CrimeLab中的Crime数据,如下面的代码

public void onPause(){

super.onPause();

CrimeLab.get(getActivity()).updateCrime(mCrime);

}

(3)而对于需要读取数据的时候,我们就需要使用到SQLiteDatabase.query()方法了query()方法由许多个,我们应该使用下面的方法。

public Cursor query (String table,String[] columns,String where,String[] whereArgs,String groupBy,String having,String orderBy,String limit)

我们应该在模型类中去调用这个方法来查询CrimeTable的记录,在这个模型类中新建一个私有方法

private Cursor queryCrimes(String whereClause,String[] whereArgs) {

Cursor cursor = mDatabase.query(

CrimeTable.NAME,null,whereClause,whereArgs,null,null,null

);

return cursor;

}

六.而对于从cursor获取数据来说,都需要有下面的代码的

String uuidString = cursor.getString(cursor.getColumnIndex(CrimeTable.Cols.UUID));这样的代码,每获取一条记录都需要有这样重复都太过重复了,那么我们应该创建专用的Cursor的子类,创建Cursor的子类的最简单的方法就是使用CursorWraapper

在数据库包中新建立CrimeCursorWrapper类

public class CrimeCursorWrapper extends CursorWrapper {

public CrimeCursorWrapper(Cursor cursor){

super(cursor);

}

}

上面创建了一个Cursor封装类,该类拥有Cursor的全部方法,这样封装的目的就是用来新创建新的方法,以方便操作内部的cursor

在该封装类中去增加一个getCrime()的方法

public Crime getCrime(){

String uuidString = getString(getColumnIndex(CrimeTable.Cols.UUID));

String title = getString(getColumnIndex(CrimeTable.Cols.TITLE));

return null;

}

(4)我们这边也需要返回具有UUID的Crime,所以我们需要在Crime.java中去添加一个有此用途的构造方法,

public Crime (UUID id){

mId = id;

mDate = new Date();

}

然后我们就去完成上面的在CrimeCursorWrapper的getCrime()

public Crime getCrime(){

String uuidString = getString(getColumnIndex(CrimeTable.Cols.UUID));

String title = getString(getColumnIndex(CrimeTable.Cols.UUID));

Crime crime = new Crime(UUID.fromString(uuidString));

crime.setTitle(title);

return crime;

 

}

七.而当使用CrimeCursorWrapper类后,我们就可以直接在CrimeLab中去取得List<Crime>,思路如下

我们将查询到的cursor封装到CrimeCursorWrapper类中,然后调用封装类的getCrime()方法遍历取出Crime

在CrimeLab中修改下面的方法

private CrimeCursorWrapper queryCrimes(String whereClause,String whereArgs) {

Cursor cursor = mDatabase.query(CrimeTable.NAME,null,whereClause,whereArgs,null,null,null);

return new CrimeCursorWrapper(cursor);

}

然后在CrimeLab类中去返回列表

public List<Crime> getCrimes(){

List<Crime> crimes = new ArrayList<>();

CrimeCursorWrapper  cursor = queryCrimes(null,null);

try{

cursor.moveToFirst();

while(!cursor.isAfterLast()){

crimes.add(cursor.getCrime());

cursor.moveToNext();

}

}finally{

cursor.close();

}

return crimes;

}

 

对于cursor来说,最后需要调用cursor的close()方法来关闭它

而对于CrimeLab来说,也可以通过getCrime(UUID id)方法来获得某条特定的书据的第一条,如下面的代码

public Crime getCrime(UUID id) {

CrimeCursorWrapper cursor = queryCrimes(CrimeTable.Cols.UUID + " = ?",new String[] { id.toString()});

try{

if(cursor.getCount() == 0){

return null;

}

cursor.moveToFirst();

return cursor.getCrime();

} finally {

cursor.close();

}

}

八.但此时模型层还需要刷新才会显示出来数据,这是因为虽然Crime记录已经存入数据库中,但是数据读取还没有完善,例如我们编辑好新的crime后,点击后退键,此时我们就会发现CrimeListActivity并没有更新刷新,原因在于之前只有一个List<Crime>,而且每一个Crime在List<Crime>只存在一个对象,要获取哪一个crime只能去寻找crimes,但现在crimes已经废弃不用了,而getCrimes()方法中的List<Crime>是Crime对象的快照,要刷新CrimeListActivity界面,首先就需要更新这个快照

 

要刷新crime显示,首先需要在CrimeListFragment类中添加下面的代码

public void setCrimes(List<Crime> crimes){

mCrimes = crimes;

}

然后在updateUI方法中去调用setCrimes()方法,如下面的代码

private void updateUIU(){

CrimeLab crimeLab = CrimeLab.get(getActivity());

List<Crime> crimes = crimeLab.getCrimes();

if(mAdapter == null){

mAdapter = new CrimeAdapter(crimes);

mCrimeRecyclerView.setAdapter(mAdapter);

} else{

mAdapter.setCrimes(crimes);

mAdapter.notifyDataSetChanged();

}

updateSubtitle();

}

这样后,当我们增加新的一条记录,然后后退键,就会发现在CrimeListActivity中已经出现了刚才增加的记录。

十.应用上下文作用,在前面,我们已经发现了在CrimeLab的构造方法中去使用了应用上下文,private CrimeLab(Context context) {

mContext = context.getApplicationContext();

}

应用上下文的话,只要有activity存在,那么Android就会创建了Application对象,用户在不同的activity之间导航时,activity有时消失了,但是application不会受到伤害的,CrimeLab是一个单例,这表明一旦创建了它就会一直存在,直到整个进程都消失,这边也可以看出CrimeLab引用着mContext对象,为了避免资源浪费,我们使用了应用上下文,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值