m内容提供器(Content Provider)主要用于不同应用程序之间实现数据共享的功能,提供一套完整的机制,允许一个程序访问另一个程序中的数据,同时还保证被访数据的安全性
1. 运行时权限
Android 中有上百种系统功能、传感器,当应用软件需要使用该功能时,需要获得其运行时权限
已拨打电话 ACTION_CALL为例
public class ProviderActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_provider);
Button makeCall = findViewById(R.id.make_call);
makeCall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//判断用户是否已授权
if(ContextCompat.checkSelfPermission(ProviderActivity.this, Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(ProviderActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);
}else{
call();
}
}
});
}
private void call(){
try {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}catch (SecurityException e){
e.printStackTrace();
}
}
//调用完requestPermissions方法后,系统会弹出一个权限申请的对话框,无论用户拒绝或者同意我们的权限申请,都会回调onRequestPermissionsResult方法
@Override
public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
call();
}else{
Toast.makeText(this,"您已拒绝同意该权限",Toast.LENGTH_LONG).show();
}
}
}
}
另外需要在AndroidManifest.xml中声明如下权限
<uses-permission android:name="android.permission.CALL_PHONE" />
2. 访问其他程序中的数据
其中ContentProvider负责
- 组织应用程序的数据;
- 向其他应用程序提供数据;
ContentResolver则负责
- 获取ContentProvider提供的数据;
- 修改/添加/删除更新数据等;
对于每一个应用程序来说, 如果想要访问内容提供器中共享的数据, 就一定要借助ContentResolver类, 可以通过Context中的getContentResolver() 方法获取到该类的实例。
ContentResolver中提供了一系列的方法用于对数据进行CRUD操作, 其中insert() 方法用于添加数据, update() 方法用于更新数据, delete() 方法用于删除数据, query() 方法用于查询数据。
查询如下方法所示
Cursor cursor = getContentResolver().query(
uri,
projection,
selection,
selectionArgs,
sortOrder);
读取系统联系人
//读取系统联系人
ListView contactsView = findViewById(R.id.contacts_view);
adapter = new ArrayAdapter<String>(this, android.R.layout. simple_list_item_1, contactsList);
contactsView.setAdapter(adapter);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS }, 1);
} else {
Cursor cursor = null;
try {
// 查询联系人数据
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
// 获取联系人姓名
String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
// 获取联系人手机号
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactsList.add(displayName + "\n" + number);
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
另外需要在AndroidManifest.xml中声明如下权限
<uses-permission android:name="android.permission.READ_CONTACTS" />

3. 自定义内容提供器
databasetest项目上自定义的内容提供器
public class DatabaseProvider extends ContentProvider {
public static final int USER_DIR = 0;
public static final int USER_ITEM = 1;
public static final String AUTHORITY = "com.example.databasetest.provider";
private static UriMatcher uriMatcher;
private MyDatabaseHelper dbHelper;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "user", USER_DIR);
uriMatcher.addURI(AUTHORITY, "user/#", USER_ITEM);
}
@Override
public boolean onCreate() {
dbHelper = new MyDatabaseHelper(getContext(), "database.db", null, 2);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// 查询数据
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case USER_DIR:
cursor = db.query("User", projection, selection, selectionArgs, null, null, sortOrder);
break;
case USER_ITEM:
String userId = uri.getPathSegments().get(1);
cursor = db.query("User", projection, "id = ?", new String[] { userId }, null, null, sortOrder);
break;
default:
break;
}
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 添加数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
Uri uriReturn = null;
switch (uriMatcher.match(uri)) {
case USER_DIR:
case USER_ITEM:
long newUserId = db.insert("User", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/user/" + newUserId);
break;
default:
break;
}
return uriReturn;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// 更新数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
int updatedRows = 0;
switch (uriMatcher.match(uri)) {
case USER_DIR:
updatedRows = db.update("User", values, selection, selectionArgs);
break;
case USER_ITEM:
String userId = uri.getPathSegments().get(1);
updatedRows = db.update("User", values, "id = ?", new String[] { userId });
break;
default:
break;
}
return updatedRows;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 删除数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
int deletedRows = 0;
switch (uriMatcher.match(uri)) {
case USER_DIR:
deletedRows = db.delete("User", selection, selectionArgs);
break;
case USER_ITEM:
String bookId = uri.getPathSegments().get(1);
deletedRows = db.delete("User", "id = ?", new String[] { bookId });
break;
default:
break;
}
return deletedRows;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case USER_DIR:
return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.user";
case USER_ITEM:
return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.user";
}
return null;
}
MyProject项目上 实现ContentResolver对databasetest项目中内容进行提取
Button addProvideData = (Button) findViewById(R.id.add_provide_data);
addProvideData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 添加数据
Uri uri = Uri.parse("content://com.example.databasetest.provider/user");
ContentValues values = new ContentValues();
values.put("username", "jjj");
values.put("height", 55);
values.put("age", 11);
Uri newUri = getContentResolver().insert(uri, values);
newId = newUri.getPathSegments().get(1);
}
});
Button queryProvideData = (Button) findViewById(R.id.query_provide_data);
queryProvideData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 查询数据
Uri uri = Uri.parse("content://com.example.databasetest.provider/user");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String username = cursor.getString(cursor. getColumnIndex("username"));
double height = cursor.getDouble(cursor. getColumnIndex("height"));
int age = cursor.getInt(cursor.getColumnIndex ("age"));
Log.d("ProviderActivity", "姓名" + username);
Log.d("ProviderActivity", "身高" + height);
Log.d("ProviderActivity", "年龄 " + age);
}
cursor.close();
}
}
});
Button updateProvideData = (Button) findViewById(R.id.update_provide_data);
updateProvideData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 更新数据
Uri uri = Uri.parse("content://com.example.databasetest.provider/user/" + newId);
ContentValues values = new ContentValues();
values.put("age", 1216);
getContentResolver().update(uri, values, null, null);
}
});
Button deleteProvideData = (Button) findViewById(R.id.delete_provide_data);
deleteProvideData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 删除数据
Uri uri = Uri.parse("content://com.example.databasetest.provider/user/" + newId);
getContentResolver().delete(uri, null, null);
}
});
由于 Android10版本过高
需要在两个项目中AndroidManifest.xml添加权限认可
//内容提取项目这边
<queries>
<package android:name="com.example.databasetest" />
<!-- 也可以单独指定provider -->
<!-- <provider android:authorities="com.example.databasetest.provider" />-->
</queries>
//内容提供项目侧
<permission
android:name="DatabaseProvider._WRITE_PERMISSION"
android:protectionLevel="normal" />