讲解最全面的文章:https://www.jianshu.com/p/ea8bc4aaf057
首先对ConetentProvider有一个整体的认识:
1:它的作用就是实现数据共享,其实他不参与数据的具体存储,只是提供了进程间数据共享操作的接口,提供给我们方法实现 对数据的各种操作。他的底层就是aidl Binder机制实现。
1:其实具体需要什么系统已经为我们搭建好了: 我们只需要实现根据自己的需求实现这几个api即可对外提供共享数据的 能力。
2:另外注意几个辅助工具类:ConetntResolver类 ContentUris UriMatcher类 ConetentObserver类
3:提供数据的规则 数据类型限制
@Override public boolean onCreate() { return false; } @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } @Nullable @Override public String getType(Uri uri) { return null; } @Nullable @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; }
1:方法详解
<-- 4个核心方法 -->
public Uri insert(Uri uri, ContentValues values)
// 外部进程向 ContentProvider 中添加数据
public int delete(Uri uri, String selection, String[] selectionArgs)
// 外部进程 删除 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
// 外部进程更新 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
// 外部应用 获取 ContentProvider 中的数据
// 注: // 1. 上述4个方法由外部进程回调,并运行在ContentProvider进程的Binder线程池中(不是主线程)
// 2. 存在多线程并发访问,需要实现线程同步
// a. 若ContentProvider的数据存储方式是使用SQLite & 一个,则不需要,因为SQLite内部实现好了线程同步,若是多个SQLite则需要,因为SQL对象之间无法进行线程同步
// b. 若ContentProvider的数据存储方式是内存,则需要自己实现线程同步
<-- 2个其他方法 -->
public boolean onCreate()
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作
public String getType(Uri uri)
// 得到数据类型,即返回当前 Url 所代表数据的MIME类型
3:数据规则,数据类型限制,
统一的资源标识符,URI,按照这个规则创建数据和对外提供数据。
URI规则 协议(Schema)+授权信息(Authority)+表名(Path)+具体id(name 字段)(ID)
ContentProvider规定协议是conetnt 授权信息(自定义,作为你的CotentProvider的唯一标示 一般使用包名)Path一般使用 表名 一般 也可以其他的名称。 对应比较协调 包名+表名+表中属性。
eg:content://stbauthinfo/authentication/username
数据类型有类型和子类型组成。MIME
ContentProvider一般以表格形式组织数据。
android中常见数据库操作详解
SQLiteOpenHelper
1:是一个管理数据库 可以实现数据库创建和版本控制的类
2:他是一个抽象类 需要实现onCreate onUpgrade onOpen
在创建的时候需要保证不存在 再打开时需要保证存在
常用api详解:
1:getReadableDatabase() 获取一个可读数据库 SQliteDatabase
2:getWritableDatabase() 获取一个可写数据库
3:onCreate() 数据库第一次创建的时候会调用
4:onUpgrade() 数据库升级的时候调用
5:close() 关闭数据库
6:query() 数据库查询
7:delete() 删除操作
8:insert() 插入操作
9:update() 更新数据操作
10:execSQL() 执行一个sql语句
细节详解:
// 数据库版本号 private static Integer Version = 1;
/** * 构造函数 * 在SQLiteOpenHelper的子类中,必须有该构造函数 */
public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
{
// 参数说明
// context:上下文对象
// name:数据库名称
// param:一个可选的游标工厂(通常是 Null)
// version:当前数据库的版本,值必须是整数并且是递增的状态
// 必须通过super调用父类的构造函数
super(context, name, factory, version);
}
/** * 复写onCreate() * 调用时刻:当数据库第1次创建时调用 * 作用:创建数据库 表 & 初始化数据
* SQLite数据库创建支持的数据类型: 整型数据、字符串类型、日期类型、二进制 */
@Override public void onCreate(SQLiteDatabase db)
{
// 创建数据库1张表
// 通过execSQL()执行SQL语句(此处创建了1个名为person的表)
String sql = "create table person(id integer primary key autoincrement,name varchar(64),address varchar(64))";
db.execSQL(sql);
// 注:数据库实际上是没被创建 / 打开的(因该方法还没调用)
// 直到getWritableDatabase() / getReadableDatabase() 第一次被调用时才会进行创建 / 打开
}
/** * 复写onUpgrade() * 调用时刻:当数据库升级时则自动调用(即 数据库版本 发生变化时)
* 作用:更新数据库表结构 * 注:创建SQLiteOpenHelper子类对象时,必须传入一个version参数,
该参数 = 当前数据库版本, 若该版本高于之前版本, 就调用onUpgrade() */
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{ // 参数说明:
// db : 数据库
// oldVersion : 旧版本数据库
// newVersion : 新版本数据库
// 使用 SQL的ALTER语句
String sql = "alter table person add sex varchar(8)"; db.execSQL(sql);
}
SQLiteDatabase :将操作数据的方法暴露出来,真正实现数据库操作的相关api 创建数据库 增删改查api的实现
注意上面的类也是支持sql语句相关操作
关键api详解
插入操作:
// a. 创建DatabaseHelper对象
// 注:一定要传入最新的数据库版本号
SQLiteOpenHelper dbHelper = new DatabaseHelper(SQLiteActivity.this,"test_carson",2);
// b.创建 or 打开 可读/写的数据库
SQLiteDatabase sqliteDatabase = dbHelper.getWritableDatabase();
/** * 操作1:插入数据 = insert() */
// a. 创建ContentValues对象
ContentValues values = new ContentValues();
// b. 向该对象中插入键值对
values.put("id", 1);
values.put("name", "carson");
//其中,key = 列名,value = 插入的值
//注:ContentValues内部实现 = HashMap,区别在于:ContenValues Key只能是String类型,Value可存储基本类型数据 & String类型
// c. 插入数据到数据库当中:insert()
sqliteDatabase.insert("user", null, values);
// 参数1:要操作的表名称
// 参数2:SQl不允许一个空列,若ContentValues是空,那么这一列被明确的指明为NULL值
// 参数3:ContentValues对象
// 注:也可采用SQL语句插入
String sql = "insert into user (id,name) values (1,'carson')";
db.execSQL(sql) ;
/** * 操作2:修改数据 = update() */
// a. 创建一个ContentValues对象
ContentValues values = new ContentValues();
values.put("name", "zhangsan");
// b. 调用update方法修改数据库:将id=1 修改成 name = zhangsan
sqliteDatabase.update("user", values, "id=?", new String[] { "1" });
// 参数1:表名(String)
// 参数2:需修改的ContentValues对象
// 参数3:WHERE表达式(String),需数据更新的行; 若该参数为 null, 就会修改所有行;?号是占位符 /
/ 参数4:WHERE选择语句的参数(String[]), 逐个替换 WHERE表达式中 的“?”占位符;
// 注:调用完upgrate()后,则会回调 数据库子类的onUpgrade()
// 注:也可采用SQL语句修改
String sql = "update [user] set name = 'zhangsan' where id="1";
db.execSQL(sql);
/** * 操作3:删除数据 = delete() */
// 删除 id = 1的数据
sqliteDatabase.delete("user", "id=?", new String[]{"1"});
// 参数1:表名(String)
// 参数2:WHERE表达式(String),需删除数据的行; 若该参数为 null, 就会删除所有行;?号是占位符
// 参数3:WHERE选择语句的参数(String[]), 逐个替换 WHERE表达式中 的“?”占位符;
// 注:也可采用SQL语句修改
String sql = "delete from user where id="1";
db.execSQL(sql);
ContentProvider实现数据共享
ContentResolver
注意跨进程通信:在调用获取数据 刷新数据 等等操作的的时候 最终会调用到提供数据共享的apk里面的ContentProvider里面的
ContentProvider的相关api 所以需要实现好增删改查相关方法的实现。