1.开发contentProvider子类
1、创建一个ContentProvider的子类MyContentProvider
public class MyFirstContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.d("nc", "onCreate: 方法被调用");
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
Log.d("nc",uri.toString()+ "query:方法被调用 ");
Log.d("nc","where 参数为: "+selection);
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
2、编辑Manifest文件,指定name为刚才创建的类,指定authorities为项目名.dictprovider
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.myex142contentprovider">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name=".MyFirstContentProvider"
android:authorities="com.fengray.myex142contentprovider.dictprovider"
android:exported="true"/>
</application>
</manifest>
3、将自定义子类添加到activity里
public class MainActivity extends AppCompatActivity {
private Button mybtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mybtn=findViewById(R.id.btnContentProvider);
mybtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyFirstContentProvider contentProvider=new MyFirstContentProvider();
}
});
}
}
2.使用ContentResolver调用方法
1、创建自定义ContentProvider类MyFirstContentProvider
2、注册Manifest文件
3、主布局文件
4、主activity文件
1、自定义contengprovider类
public class MyFirstContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.d("nc", "onCreate: 方法被调用");
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
//Log.d("nc", "query: ====================");
System.out.print("==============================");
Log.d("nc",uri.toString()+ "query:方法被调用 ");
Log.d("nc","selection 参数为: "+selection);
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
Log.d("nc", uri.toString()+"insert: 方法被调用 ");
Log.d("nc", "values的参数为:"+values);
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
Log.d("nc", uri.toString()+"delete: 方法被调用");
Log.d("nc", "selection valuese is "+selection);
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
Log.d("nc", uri.toString()+"update: 方法被调用");
Log.d("nc", "update: selection参数为:"+selection+" contentValues is "+values);
return 0;
}
}
2、注册manifest文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.myex142contentprovider">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name=".MyFirstContentProvider"//自定义的类名
android:authorities="com.fengray.myex142contentprovider.dictprovider"//authority名
android:exported="true"/>
</application>
</manifest>
3、布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn1delete"
android:text="onDelete"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn2query"
android:text="onQuery"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn3insert"
android:text="onInsert"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn4update"
android:text="onUpdate"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
4、activity文件
public class MainActivity extends AppCompatActivity {
private Button btnquery,btninsert,btndelete,btnUpdate;
//这个uri字符串与manifest文件里的authority名一致,注意项目名称后面不是跟ContentProvider的类名
private Uri uri=Uri.parse("content://com.fengray.myex142contentprovider.dictprovider/");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnquery=findViewById(R.id.btn2query);
btndelete=findViewById(R.id.btn1delete);
btninsert=findViewById(R.id.btn3insert);
btnUpdate=findViewById(R.id.btn4update);
btnquery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
query(v);
}
});
btninsert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
insert(v);
}
});
btnUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
update(v);
}
});
btndelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
delete(v);
}
});
}
public void query(View source){
//调用ContentResolver的query方法,实际返回的是Uri对应的contentProvider的query返回的值
Cursor cursor=getContentResolver().query(uri,null,"query_where",null,null);
Toast.makeText(this,"远程contentProvider返回的Cursor为:"+cursor,Toast.LENGTH_SHORT).show();
}
public void insert(View view){
//实际调用都是uri对应的ContentProvider
ContentValues values = new ContentValues();
values.put("name","ncepu");
Uri newuri = getContentResolver().insert(uri,values);
Toast.makeText(this,"远程contentProvider插入的uri为:"+newuri,Toast.LENGTH_SHORT).show();
}
public void update(View view){
//实际调用都是uri对应的ContentProvider
ContentValues contentValues=new ContentValues();
contentValues.put("name","tingshua");
int count=getContentResolver().update(uri,contentValues,"new_values",null);
Toast.makeText(this,"远程contentProvider更新的数为"+count,Toast.LENGTH_SHORT).show();
}
public void delete(View view){
//实际调用都是uri对应的ContentProvider
int count=getContentResolver().delete(uri,"delet_where",null);
Toast.makeText(this,"远程contentProvider删除的记录数为"+count,Toast.LENGTH_SHORT).show();
}
}
3.操作系统的ContentResolver
1、string资源文档
<resources>
<string name="app_name">SysProvider</string>
<string name="search">查询</string>
<string name="add">添加</string>
<string name="name">联系人姓名</string>
<string name="phone">电话</string>
<string name="email">Email</string>
<string name="permission_tip">您必须授予程序读写联系人信息的权限</string>
</resources>
2.Manifest文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<!-- 授予读联系人ContentProvider的权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- 授予写联系人ContentProvider的权限 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3、布局文件
reult.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ExpandableListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/list"
android:groupIndicator="@drawable/user"/>
</LinearLayout>
主布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal">
<Button
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search"/>
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="@string/name"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/name"
android:padding="4dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="@string/phone"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/phone"
android:padding="4dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/email"
android:padding="4dp"
android:inputType="textEmailAddress"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/email"
android:padding="4dp"/>
</LinearLayout>
4、activity文件
public class MainActivity extends AppCompatActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults[0]==0){
if (requestCode==0x123){
// 定义两个List来封装系统的联系人信息、指定联系人的电话号码、Email等详情
final List <String> names=new ArrayList<>();
final List<List<String>> details=new ArrayList<>();
// 使用ContentResolver查找联系人数据,拿到了所有联系人的合集(结果集)
Cursor cursor=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null,null,null);
// 遍历查询结果,获取系统中所有联系人
while (cursor.moveToNext()){
// 获取联系人ID
String contactId=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
// 获取联系人的名字
String name=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
names.add(name);
// 使用ContentResolver查找联系人的电话号码
Cursor phones=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+contactId,null,null);
List<String> detail=new ArrayList<>();
// 遍历查询结果,获取该联系人的多个电话号码
while(phones.moveToNext()){
// 获取查询结果中电话号码列中数据
String phoneNumber=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
detail.add("电话号码:"+phoneNumber);
}
phones.close();
// 使用ContentResolver查找联系人的E-mail地址
Cursor emails=getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,ContactsContract.CommonDataKinds.Email.CONTACT_ID+"="+contactId,null,null);
// 遍历查询结果,获取该联系人的多个E-mail地址
while(emails.moveToNext()){
// 获取查询结果中E-mail地址列中数据
String emailAddress=emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
detail.add("邮件地址:"+emailAddress);
emails.close();
details.add(detail);
}
cursor.close();
// 加载result.xml界面布局代表的视图
View resultDialog=getLayoutInflater().inflate(R.layout.result,null);
// 获取resultDialog中ID为list的ExpandableListView
ExpandableListView listView = resultDialog.findViewById(R.id.list);
// 创建一个ExpandableListAdapter对象
ExpandableListAdapter adapter=new BaseExpandableListAdapter() {
@Override
public int getGroupCount() {
return names.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return details.get(groupPosition).size();
}
// 获取指定组位置处的组数据
@Override
public Object getGroup(int groupPosition) {
return names.get(groupPosition);
}
// 获取指定组位置、指定子列表项处的子列表项数据
@Override
public Object getChild(int groupPosition, int childPosition) {
return details.get(groupPosition).get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return true;
}
// 该方法决定每个组选项的外观
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
TextView textView;
if (convertView==null){
textView=createTextView();
}else{
textView=(TextView) convertView;
}
textView.setTextSize(18f);
textView.setPadding(90,10,0,10);
textView.setText(getGroup(groupPosition).toString());
return textView;
}
// 该方法决定每个子选项的外观
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
TextView textView;
if (convertView==null){
textView=createTextView();
}else{
textView=(TextView) convertView;
}
textView.setText(getChild(groupPosition,childPosition).toString());
return textView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
private TextView createTextView(){
AbsListView.LayoutParams layoutParams=new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.WRAP_CONTENT);
TextView textView=new TextView(MainActivity.this);
textView.setLayoutParams(layoutParams);
textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.START);
textView.setPadding(40,5,0,5);
textView.setTextSize(15f);
return textView;
}
};
// 为ExpandableListView设置Adapter对象
listView.setAdapter(adapter);
// 使用对话框来显示查询结果
new AlertDialog.Builder(MainActivity.this).setView(resultDialog).setPositiveButton("确定",null).show();
}
if (requestCode==0x456){
// 获取程序界面中的三个文本框的内容
String name=((EditText)findViewById(R.id.name)).getText().toString().trim();
String phone=((EditText)findViewById(R.id.phone)).getText().toString().trim();
String email=((EditText)findViewById(R.id.email)).getText().toString().trim();
if (name.equals("")){
return;
}
// 创建一个空的ContentValues
ContentValues values=new ContentValues();
// 向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId
Uri rawContentUri=getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI,values);
long rawContactId= ContentUris.parseId(rawContentUri);
values.clear();
values.put(ContactsContract.RawContacts.Data.RAW_CONTACT_ID,rawContactId);
// 设置内容类型
values.put(ContactsContract.RawContacts.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
// 设置联系人名字
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,name);
// 向联系人URI添加联系人名字
getContentResolver().insert(ContactsContract.Data.CONTENT_URI,values);
values.clear();
values.put(ContactsContract.RawContacts.Data.RAW_CONTACT_ID,rawContactId);
values.put(ContactsContract.RawContacts.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
// 设置联系人的电话号码
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
// 设置电话类型
values.put(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
// 向联系人电话号码URI添加电话号码
getContentResolver().insert(ContactsContract.Data.CONTENT_URI,values);
values.clear();
values.put(ContactsContract.RawContacts.Data.RAW_CONTACT_ID,rawContactId);
values.put(ContactsContract.RawContacts.Data.MIMETYPE,ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
// 设置联系人的E-mail地址
values.put(ContactsContract.CommonDataKinds.Email.DATA,email);
// 设置该电子邮件的类型
values.put(ContactsContract.CommonDataKinds.Email.TYPE,ContactsContract.CommonDataKinds.Email.TYPE_WORK);
// 向联系人E-mail URI添加E-mail数据
getContentResolver().insert(ContactsContract.Data.CONTENT_URI,values);
Toast.makeText(MainActivity.this, "联系人数据添加成功", Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(this, R.string.permission_tip, Toast.LENGTH_SHORT)
.show();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button searchBn=findViewById(R.id.search);
Button addBn=findViewById(R.id.add);
searchBn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 请求读取联系人信息的权限
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0x123);
}
});
// 为addBn按钮的单击事件绑定监听器
addBn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 请求写入联系人信息的权限
requestPermissions(new String[]{Manifest.permission.WRITE_CONTACTS}, 0x456);
}
});
}
}
这个例子由于android6以上的安全机制始终拿不到读写权限,所以考虑单独写个类CheckPermissionsActivity,做权限许可,并由主activity继承这个类(这个类本身也继承自Activity类)
/**
* 继承了Activity,实现Android6.0的运行时权限检测
* 需要进行运行时权限检测的Activity可以继承这个类
*
* @项目名称: AMapLocationDemo
* @文件名称:PermissionsChecker.java
* @类型名称:PermissionsChecker
* @since 2.5.0
*/
public class CheckPermissionsActivity extends AppCompatActivity
implements
ActivityCompat.OnRequestPermissionsResultCallback {
/**
* 需要进行检测的权限数组
*/
protected String[] needPermissions = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.DISABLE_KEYGUARD,
Manifest.permission.RECEIVE_BOOT_COMPLETED,
Manifest.permission.READ_CONTACTS,
};
private static final int PERMISSON_REQUESTCODE = 0;
/**
* 判断是否需要检测,防止不停的弹框
*/
private boolean isNeedCheck = true;
@Override
protected void onResume() {
super.onResume();
if(isNeedCheck){
checkPermissions(needPermissions);
}
}
private void checkPermissions(String... permissions) {
List<String> needRequestPermissonList = findDeniedPermissions(permissions);
if (null != needRequestPermissonList
&& needRequestPermissonList.size() > 0) {
ActivityCompat.requestPermissions(this,
needRequestPermissonList.toArray(
new String[needRequestPermissonList.size()]),
PERMISSON_REQUESTCODE);
}
}
/**
* 获取权限集中需要申请权限的列表
*
* @param permissions
* @return
* @since 2.5.0
*
*/
private List<String> findDeniedPermissions(String[] permissions) {
List<String> needRequestPermissonList = new ArrayList<String>();
for (String perm : permissions) {
if (ContextCompat.checkSelfPermission(this,
perm) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.shouldShowRequestPermissionRationale(
this, perm)) {
needRequestPermissonList.add(perm);
}
}
return needRequestPermissonList;
}
/**
* 检测是否说有的权限都已经授权
* @param grantResults
* @return
* @since 2.5.0
*
*/
private boolean verifyPermissions(int[] grantResults) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] paramArrayOfInt) {
if (requestCode == PERMISSON_REQUESTCODE) {
if (!verifyPermissions(paramArrayOfInt)) {
showMissingPermissionDialog();
isNeedCheck = false;
}
}
}
/**
* 显示提示信息
*
* @since 2.5.0
*
*/
private void showMissingPermissionDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("权限要求");
builder.setMessage("设置权限");
// 拒绝, 退出应用
builder.setNegativeButton("cancel",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.setPositiveButton("setting",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startAppSettings();
}
});
builder.setCancelable(false);
builder.show();
}
/**
* 启动应用的设置
*
* @since 2.5.0
*
*/
private void startAppSettings() {
Intent intent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK){
this.finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
}