博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android之数据库和Content Provider(一)
阅读量:5808 次
发布时间:2019-06-18

本文共 7741 字,大约阅读时间需要 25 分钟。

hot3.png

安卓SQLite数据库所创建的数据是私有与所创建的应用程序。通过Content Provider给外接提供接口,从而其它的APP可以通过此来访问。

Content Provider基于一个简单的URI地址模型:使用 content:// 模式(schema).  它使你的应用程序层与数据层去耦合。

 

通常比较好的,你需要去封装一些公有的方法和常量作为与底层数据库交互的需要。通常封装到一个类中,而这种类通常称为XXContact或者XXHelper。

例子:片段

// The index (key) column name for use in where clauses. public static final String KEY_ID = “_id”;// The name and column index of each column in your database. // These should be descriptive. public static final String KEY_GOLD_HOARD_NAME_COLUMN =     “GOLD_HOARD_NAME_COLUMN”; public static final String KEY_GOLD_HOARD_ACCESSIBLE_COLUMN =     “OLD_HOARD_ACCESSIBLE_COLUMN”; public static final String KEY_GOLD_HOARDED_COLUMN =     “GOLD_HOARDED_COLUMN”; // TODO: Create public field for each column in your table.

 

介绍SQLiteOpenHelper

SQLiteOpenHelper是一个抽象类,用来创建,打开,更新数据库。

通过实现这样一个抽象类,你可以隐藏你的逻辑是否一个数据库在打开前需要被创建或者更新,同时确保每个操作都是被有效得完成。

比较好的方式:推迟创建和打开数据库,直到他们需要的时候。

除非你不需要使用当前的SQLite数据库了,否则打开后就先不要关闭它。

注意:数据库操作,尤其是打开或者创建数据库是比较耗时的。为了确保用户体验,应该让所有的数据库事务都异步进行。

例子:实现SQLiteOpenHelper

private static class HoardDBOpenHelper extends SQLiteOpenHelper {          private static final String DATABASE_NAME = “myDatabase.db”;           private static final String DATABASE_TABLE = “GoldHoards”;           private static final int DATABASE_VERSION = 1;          // SQL Statement to create a new database.           private static final String DATABASE_CREATE = “create table “ +             DATABASE_TABLE + “ (“ + KEY_ID +             “ integer primary key autoincrement, “ +             KEY_GOLD_HOARD_NAME_COLUMN + “ text not null, “ +             KEY_GOLD_HOARDED_COLUMN + “ float, “ +             KEY_GOLD_HOARD_ACCESSIBLE_COLUMN + “ integer);”;          public HoardDBOpenHelper(Context context, String name,                                 CursorFactory factory, int version) {             super(context, name, factory, version);           }          // Called when no database exists in disk and the helper class needs           // to create a new one.           @Override           public void onCreate(SQLiteDatabase db) {             db.execSQL(DATABASE_CREATE);           }          // Called when there is a database version mismatch meaning that           // the version of the database on disk needs to be upgraded to          // the current version.         @Override         public void onUpgrade(SQLiteDatabase db, int oldVersion,                                   int newVersion) {         // Log the version upgrade.        Log.w(“TaskDBAdapter”, “Upgrading from version “ +           oldVersion + “ to “ +           newVersion + “, which will destroy all old data”);       // Upgrade the existing database to conform to the new        // version. Multiple previous versions can be handled by        // comparing oldVersion and newVersion values.       // The simplest case is to drop the old table and create a new one.        db.execSQL(“DROP TABLE IF IT EXISTS “ + DATABASE_TABLE);        // Create a new one.        onCreate(db);      }  }

 

在这个例子中,onUpgrade简单得删除了表,然后再重新创建。这是最简单和实用解决方式。但是,若一些重要数据无法通过网络同步,一个好的方式就是将存在的数据移植到新的表中。

程序中实用SQLiteHelper去获取一个数据库有2种方式:

1.getWritableDatabase  可读可写

2.getReadableDatabase  只读

如果数据库不存在,则helper类执行onCreate方法。如果数据库版本发生改变,则执行onUpgrade方法。

当数据库被成功打开,SQLiteHelper会缓存它,所以你可以随时对数据库进行操作。

 

不用SQLiteHelper去打开和创建数据库

如果你想直接去管理创建,打开和版本控制数据库.你可以使用APP的Context的openOrCreateDatabase方法,自己去创建数据库。

SQLiteDatabase db = context.openOrCreateDatabase(DATABASE_NAME,Context.MODE_PRIVATE, null);

通常比较好的方式:需要使用数据库的时候再去创建或者打开它,打开成功后然后缓存数据库实例,考虑到效率的问题。

最最少的,这些对数据库的操作都应该异步进行,不然可能会影响主APP进程。

 

安卓数据库设计考虑

1.文件(位图,视频文件)通常不直接存放在数据库表中。使用一个字符串去存储它的文件路径,更好的方式有一个完整合格的URI。

2.尽管不是严格的一个要求,通常还是强烈推荐所有的表都应该包含一个自动增长字段,作为每行的唯一索引字段。如果你计划通过Content Provider去共享你的表,这个唯一的ID字段就需要了。

 

查询数据库

每个数据库查询都返回一个Cursor。通过获取和释放行和列的值,这使安卓管理资源更加有效率。

查询数据库例子:

// Specify the result column projection. Return the minimum set // of columns required to satisfy your requirements. String[] result_columns = new String[] {   KEY_ID, KEY_GOLD_HOARD_ACCESSIBLE_COLUMN, KEY_GOLD_HOARDED_COLUMN };// Specify the where clause that will limit our results. String where = KEY_GOLD_HOARD_ACCESSIBLE_COLUMN + “=” + 1;// Replace these with valid SQL statements as necessary. String whereArgs[] = null; String groupBy = null; String having = null; String order = null;SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); Cursor cursor = db.query(HoardDBOpenHelper.DATABASE_TABLE,                               result_columns, where,                               whereArgs, groupBy, having, order);
从Cursor中提取值

使用moveTo<location>方法, 接着有getColumnIndexOrThrow和getColumnIndex,前者是若找不到该列会抛出异常,而后者:若返回的是-1,则表示该列不存在。

任何时候某列不存在,后者更有效些,例子:

int columnIndex = cursor.getColumnIndex(KEY_COLUMN_1_NAME); if (columnIndex > -1) {      String columnValue = cursor.getString(columnIndex);      // Do something with the column value. }   else {      // Do something else if the column doesn’t exist. }

 

注意:你应该提供数共有的数据库列名静态常量,就像我们之前提到的那样,通过Contract或者Helper类去封装,或者通过Content Provider。

从Curor中获取值 例子:

float totalHoard = 0f; float averageHoard = 0f;// Find the index to the column(s) being used. int GOLD_HOARDED_COLUMN_INDEX = cursor.getColumnIndexOrThrow(KEY_GOLD_HOARDED_COLUMN);// Iterate over the cursors rows. // The Cursor is initialized at before first, so we can // check only if there is a “next” row available. If the // result Cursor is empty this will return false. while (cursor.moveToNext()) {      float hoard = cursor.getFloat(GOLD_HOARDED_COLUMN_INDEX);      totalHoard += hoard;  }// Calculate an average -- checking for divide by zero errors. float cursorCount = cursor.getCount();averageHoard = cursorCount > 0 ?                      (totalHoard / cursorCount) : Float.NaN;// Close the Cursor when you’ve finished with it. cursor.close();

 

注意:因为SQLite数据库是弱类型的,所以你获取值的时候,比如上述值是float型的,你也可以获取字符串型的。

当你完成一个查询,非常重要的一点:关掉Cursor避免内存泄露和减少你的APP资源加载。

cursor.close();

 

增加,更新,和移除行

SQLiteDatabase类还有insert,delete和update方法。

1.insert

首先你需要构建一个ContentValue对象,put方法去放入每列对应的值,这里的键就是列名。从而构建一行的数据,然后再插入。

看例子:

// Create a new row of values to insert. ContentValues newValues = new ContentValues();// Assign values for each row.  newValues.put(KEY_GOLD_HOARD_NAME_COLUMN, hoardName); newValues.put(KEY_GOLD_HOARDED_COLUMN, hoardValue);  newValues.put(KEY_GOLD_HOARD_ACCESSIBLE_COLUMN, hoardAccessible); // [ ... Repeat for each column / value pair ... ]// Insert the row into your table SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); db.insert(HoardDBOpenHelper.DATABASE_TABLE, null, newValues);

 

注意:insert的第2个参数:如果你想向数据库插入一行空的数据,除了传一个空的ContentValue外,你还必须传递一个需要被显式置为空值的列名。

但是呢,通常最好的方式是你尽量避免去插入一个空的Content Value到SQLite数据库中,所以呢,这个第2个参数通常也就为null了。

2.update行

同样,你也需要一个Content Value对象去指定键/值对去更新指定列的值。

代码片段:

// Create the updated row Content Values. ContentValues updatedValues = new ContentValues();// Assign values for each row. updatedValues.put(KEY_GOLD_HOARDED_COLUMN, newHoardValue); // [ ... Repeat for each column to update ... ]// Specify a where clause the defines which rows should be // updated. Specify where arguments as necessary. String where = KEY_ID + “=” + hoardId; String whereArgs[] = null;// Update the row with the specified index with the new values. SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); db.update(HoardDBOpenHelper.DATABASE_TABLE, updatedValues,              where, whereArgs);
3.delete行

只需要指定表名和一个where语句。

代码片段:

// Specify a where clause that determines which row(s) to delete. // Specify where arguments as necessary. String where = KEY_GOLD_HOARDED_COLUMN + “=” + 0; String whereArgs[] = null;// Delete the rows that match the where clause. SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); db.delete(HoardDBOpenHelper.DATABASE_TABLE, where, whereArgs);

 

转载于:https://my.oschina.net/wangjunhe/blog/108522

你可能感兴趣的文章
linux运维基础篇 unit11
查看>>
C++ builder 中的 XMLDocument 类详解(16) – 前一个节点、后一个节点和父节点
查看>>
poj 3101Astronomy(圆周追击+分数最小公倍数)
查看>>
mongodb 持久化
查看>>
sql
查看>>
JavaScript对象模型-执行模型
查看>>
读<jquery 权威指南>[1]-选择器及DOM操作
查看>>
JavaScript总结2
查看>>
TProfiler
查看>>
Oracle之 11gR2 RAC 修改监听器端口号的步骤
查看>>
JDK QUEUE队列
查看>>
Android获取视频音频的时长的方法
查看>>
「镁客·请讲」极限元温正棋:从前端信号处理到语音识别、对话、声纹情绪与合成,要打造智能交互闭环...
查看>>
Linux-(lsof,ifconfig,route)
查看>>
6、PXE安装ESXI6.0
查看>>
Android大神博客收集
查看>>
aix 设置主机信任
查看>>
Apache、Tomcat、Nginx
查看>>
iptables
查看>>
vnx通过iscsi连接esxi主机,并挂载nfs和block
查看>>