一、创建LocationContendProvider ,并在清单文件注册
1,在清单文件注册LocationContendProvider
normal:低风险权限,只要申请了就可以使用(在AndroidManifest.xml中添加<uses-permission>标签),安装时不需要用户确认;
dangerous:高风险权限,安装时需要用户的确认才可使用;
signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;
signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)。
<permission
android:name="com.example.settinglib.LocationContentProvider.READ"
android:protectionLevel="normal" />
<permission
android:name="com.example.settinglib.LocationContentProvider.WRITE"
android:protectionLevel="signatureOrSystem" />
<provider
android:name=".sqlite.LocationContentProvider"
android:authorities="com.example.settinglib.LocationContentProvider"
android:exported="true"
android:grantUriPermissions="true"
android:process=":provider"
android:readPermission="com.example.settinglib.LocationContentProvider.READ"
android:writePermission="com.example.settinglib.LocationContentProvider.WRITE"
/>
2,创建LocationContendProvider
public class LocationContentProvider extends ContentProvider {
private Context mContext;
private SQLiteDatabase writeDb;
private LocationSqliteHelper mInstance;
//AUTHORITIES_NAME和清单文件注册的authorities相同
public static final String AUTHORITIES_NAME = "com.example.settinglib.LocationContentProvider";
private static final int LOCATION_CODE_ONE = 1;
private static final int LOCATION_CODE_TWO = 2;
// 表示不匹配任何路径的返回码
private static UriMatcher mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//添加匹配规则
/**
* authority 主机名 通过主机名来访问我暴露的数据
* path 你也可以随意 写 com.itheima.contentprovider/query
* code 匹配码
*/
static {
//如果match()方法匹配content://com.example.settinglib.LocationContentProvider/location路径,返回匹配码为1
mMatcher.addURI(AUTHORITIES_NAME, "location", LOCATION_CODE_ONE);
}
@Override
public boolean onCreate() {
mContext = getContext();
mInstance = LocationSqliteHelper.getInstance(mContext);
writeDb = mInstance.getWritableDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// 过滤URI
int match = mMatcher.match(uri);
switch (match) {
case LOCATION_CODE_ONE:
return writeDb.query(LocationSqliteHelper.Tables.TABLE_NAME,
projection,
selection, selectionArgs,
null, null, sortOrder);
}
// mInstance.close();
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
// 过滤URI
int match = mMatcher.match(uri);
switch (match) {
case LOCATION_CODE_ONE:
String tableName = getTableName(uri);
long id = writeDb.insert(tableName, null, contentValues);
// 将原有的uri跟id进行拼接从而获取新的uri
return ContentUris.withAppendedId(uri, id);//可行
}
return uri;
}
@Override
public int delete(Uri uri, String s, String[] strings) {
return 0;
}
@Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
String tableName = getTableName(uri);
//执行更新语句,得到更新的条数
return writeDb.update(tableName, contentValues, selection, selectionArgs);
}
/**
* 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
*/
private String getTableName(Uri uri) {
String tableName = null;
switch (mMatcher.match(uri)) {
case LOCATION_CODE_ONE:
tableName = LocationSqliteHelper.Tables.TABLE_NAME;
break;
}
return tableName;
}
}
二、创建LocationSqliteHelper
1,下图,就是创建表时,添加的2个字段package_name 、selected_fuzzy
2,如果不写AUTOINCREMENT,数据库中就不会显示id
3,记得要留空格
4,下载SQLiteSpy,可以查看.db文件
public class LocationSqliteHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "location.db";
private static final int DB_VERSION = 1;
private static final String ID = "_id";
private static volatile LocationSqliteHelper instance;
private LocationSqliteHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
public static class Tables{
public static final String TABLE_NAME = "location";
}
public static class IndexColums{
private static final String PACKAGE_NAME = "package_name";
private static final String SELECTED_FUZZY = "selected_fuzzy";
}
String CREATE_TABLE_LOCATION = "CREATE TABLE " + Tables.TABLE_NAME + "(" + ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT " + "," + IndexColums.PACKAGE_NAME
+ " VARCHAR(255) ,"+IndexColums.SELECTED_FUZZY + " integer " +")";
public static LocationSqliteHelper getInstance(Context context) {
if (instance == null) {
synchronized (LocationSqliteHelper.class) {
if (instance == null) {
//使用getApplicationContext的上下文,可以避免内存泄漏
instance = new LocationSqliteHelper(context.getApplicationContext());
}
}
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_TABLE_LOCATION);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//修改数据(需要升级数据库)
}
}
三、在另一个app中查询数据,
1,在清单文件注册权限
<uses-permission android:name="com.example.settinglib.LocationContentProvider.READ" />
<uses-permission android:name="com.example.settinglib.LocationContentProvider.WRITE" />
2,在通过代码curd
注:增删数据较多时,要开启子线程,最好用线程池来管理子线程。(我这里只对1条数据操作,所以不放入子线程)
1,插入数据
private String uri = "content://"+LocationContentProvider.AUTHORITIES_NAME +"/"
+ LocationSqliteHelper.Tables.TABLE_NAME;
public void insert() {
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("selected_fuzzy", 00);
values.put("package_name", "test");
Uri result = contentResolver.insert(Uri.parse(uri), values);
long parseid = ContentUris.parseId(result);
if (parseid > 0)
//添加这个,其他人使用时,注册一个监听即可,就不用每次主动发起请求,查询结果
contentResolver.notifyChange(Uri.parse(uri),null);
}
2,根据包名查询数据
private int query(String packageName) {
int is_selected_fuzzy = -1;
Cursor cursor = null;
try {
cursor = getContentResolver().query(Uri.parse(uri),
null,
"package_name=?" , new String[]{packageName+""}, null);
if (cursor != null){
while (cursor.moveToNext()) {
is_selected_fuzzy = cursor.getInt(cursor.getColumnIndex("selected_fuzzy"));
}
}
} catch (Exception e) {
Log.e("date", "get cursor is: ", e);
} finally {
try {
if (null != cursor) {
cursor.close();
}
} catch (Exception e) {
}
}
return is_selected_fuzzy;
}
3,修改数据
//插入了数据,才能修改
//插入了数据,才能修改
private void update() {
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("selected_fuzzy", 10);
values.put("package_name", "test");
contentResolver.update(Uri.parse(uri),
values, "package_name=?", new String[]{"test"});
//添加这个,其他人使用时,注册一个监听即可,就不用每次主动发起请求,查询结果
contentResolver.notifyChange(Uri.parse(uri),null);
}
四、查询的参数
projection:要查询的列名
selection:查询的条件,查询哪行的数据
selectionArgs:查询的行关键字、范围(为where的占位符提供具体的值)
sortOrder:对查询处理的结果,进行排序方式
例如:
1,根据包名查询数据
Cursor cursor = getContentResolver().query(Uri.parse(uri),
null, "package_name=?", new String[]{"test" }, null);
2,查询所有数据
Cursor cursor = getContentResolver().query(Uri.parse(uri),
null, null, null, null);3,查询package_name一列的数据
Cursor cursor = getContentResolver().query(Uri.parse(uri),
new String[]{"package_name" },, null, null, null);
四、有些情况下,Content Provider使用者想监听数据的变化,可以注册一个Observer: