一、什么是内容提供器
-
定义 :Android 四大组件之一,用于管理应用数据的跨应用共享。
-
核心功能:
-
提供统一的接口访问数据(SQLite、文件、网络等)
-
控制数据的安全访问权限
-
支持跨进程数据交互
-
主要用于在不同的应用程序之间实现数据共享的功能,允许程序访问另一个程序的数据并保证被访问数据的安全性。
内容提供器可选择对哪一部分数据进行共享。
二、运行时权限
危险权限需要在运行时处理,普通权限需要在AndroidManifest.xml文件中添加权限声明
2.1在程序运行时申请权限
以CALL_PHONE权限为例
1.修改AndroidManifest.xml文件,声明权限
XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CALL_PHONE"/>
2.修改主活动,先判断用户是否已经授权,借用ContextCompat.checkSelfPermission方法,接收两个参数,Context和具体权限名,使用返回值和PackageManager.PERMISSION_GRANTED比较,相等表示已授权,直接执行逻辑。
没有授权,调用 ActivityCompat.requestPermissions向用户申请授权,接收三个参数,Activity实例,含有要申请权限名的String数组和请求码,之后系统自动回调onRequestPermissionResult方法,授权结果封装在grantResults中,只需要判断授权结果
java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
call();
}
}
});
}
private void call(){
Intent intent=new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
public void onRequestPermissionResult(int requestCode,String[] permissions,int[] grantResults){
switch (requestCode){
case 1:
if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
call();
}else{
Toast.makeText(this,"permission",Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
用户之后在手机设置中中可以对程序危险权限进行关闭
三、访问其他程序中的数据
3.1ContentResolver的基本用法
想要访问内容提供器中共享的数据,要借助ContentResolver类,可以通过Context中的getContentResolver()方法获取到该类的实例。
ContentResolver中的CRUD操作接收Uri参数,这个参数被称为内容URI,内容URI为内容提供器中的数据建立了唯一标识符,主要由authority和path两部分组成。
-
authority:对不同应用程序进行区分,采用程序包名进行命名
-
path:对同一应用程序中的不同表区分,一般添加在authority后
得到内容URI后通过Uri.parse得到Uri对象后才能作为参数传入。
java
Uri uri=Uri.parse("content://com.example.app.provider/tabel");
查询数据
java
Cursor cursor=getContentResolver().query(uri,projection,selection,selectionArgs,sortOrder);
- uri:指定查询某个应用程序下的某一张表
- projection:指定查询的列名
- selection:指定where的约束条件
- selectionArgs:为where中的占位符提供具体的值
- sortOrder:指定查询结果的排序方式
查询完成后返回Cursor对象,可以将数据从Cursor中逐个读取出来
java
if(cursor!=null){
while (cursor.moveToNext()){
String column1=cursor.getString(cursor.getColumnIndex("column1"));
int column2=cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}
添加数据
java
ContentValues values=new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);
将待添加的数据组装到ContentValues中,然后调用ContentResolver的insert方法,传入参数uri和values
更新数据
java
ContentValues values=new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[]{"text","1"});
上述代码使用了selection和selectionArgs参数对想要更新的数据进行约束
删除数据
java
getContentResolver().delete(uri,"column2 = ?",new String[]{"1"});
调用ContentResolver的delete方法删除数据
四、创建内容提供器
1.新建一个类继承ContentProvider,需要全部重写6个抽象方法
java
public class MyProvider extends ContentProvider {
public boolean onCreate(){
return false;
}
public Cursor query(Uri uri, String[] projection,String selection,String[] selectionArgs,String sortOrder){
return null;
}
public Uri insert(Uri uri, ContentValues values){
return null;
}
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
return 0;
}
public int delete(Uri uri,String selection,String[] selectionArgs){
return 0;
}
public String getType(Uri uri){
return null;
}
}
onCreate:初始化内容提供器时调用,完成对数据库的创建和升级
query:从内容提供器中查询数据,查询结果存放在Cursor对象中返回
insert:向内容提供器中添加一条数据,返回一个用于表示这条新记录的URI
update:更新已有数据,返回受影响的行数
delete:删除数据,返回被删除的行数
getType:返回相应的MIME类型
URI以路径结尾表示访问该表中的所有数据,以id结尾表示访问该表中有相应id的数据
可以使用通配符的方式分别匹配这两种格式的内容URI
*:表示匹配任意长度的任意字符
#:表示匹配任意长度的数字
2.借助UriMatcher类可以实现匹配内容的URI功能
UriMatcher中提供了addURI方法,接收三个参数,authority,path和自定义代码
调用UriMatcher的match方法时,传入一个Uri对象,返回的是自定义代码,通过代码判断调用方相要调用的数据
java
public class MyProvider extends ContentProvider {
public static final int TABLE1_DIR=0;
public static final int TABLE1_ITEM=1;
public static final int TABLE2_DIR=2;
public static final int TABLE2_ITEM=3;
private static UriMatcher uriMatcher;
static {
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider","table1/#",TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR);
uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);
}
public boolean onCreate(){
return false;
}
public Cursor query(Uri uri, String[] projection,String selection,String[] selectionArgs,String sortOrder){
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
break;
case TABLE1_ITEM:
break;
case TABLE2_DIR:
break;
case TABLE2_ITEM:
break;
default:
break;
}
return null;
}
public Uri insert(Uri uri, ContentValues values){
return null;
}
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
return 0;
}
public int delete(Uri uri,String selection,String[] selectionArgs){
return 0;
}
public String getType(Uri uri){
return null;
}
}
getType是所有内容提供器必须提供的一个方法,用于获取Uri对象的MIME类型,由三部分组成:
必须以vnd开头
如果以路径结尾,则后接android.cursor.dir/,如果以id结尾,后接android.cursor.item/
最后接vnd.<authority>.<path>
java
public String getType(Uri uri){
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
default:
break;
}
return null;
}
内容提供器要在AndroidManifest.xml中注册才能使用
XML
<provider
android:name=".DatabaseProvider"
android:authorities="com.example.databasetest.provider"
android:enabled="true"
android:exported="true"></provider>