"First Line of Code" Content Provider

 

12. Content provider

Content Provider (Content Provider) is mainly used to realize the function of data sharing between different applications

 

Different from the two globally readable and writable operation modes in file storage and SharedPreferences storage, content providers can choose only which part of the data to share, so as to ensure that there is no risk of leakage of private data in our programs.

 

type:

1. Use existing content providers to read and manipulate data in corresponding programs

2. The other is to create your own content provider to provide an external access interface to the data of our program

 

The ContentResolver class provides a series of methods for CRUD operations on data

The addition, deletion and modification methods in ContentResolver do not accept the table name parameter, but use a Uri parameter instead

 

HATE:

content://com.example.app.provider/table1

content://com.example.app.provider/table2

 

Authority and path.

Permissions are used to distinguish different applications . Generally, in order to avoid conflicts, they are named by the package name.

For example, the package name of a program is com.example.app, then the permission corresponding to the program can be named com.example.app.provider .

 

Paths are used to distinguish different tables in the same application , and are usually added after permissions.

For example, there are two tables in the database of a program, table1 and table2, then the paths can be named /table1 and /table2 respectively, and then the permissions and paths are combined, and the content URI becomes com.example.app .provider/table1 and com.example.app.provider/table2.

 

1. *: means to match any character of any length

2. #: means to match numbers of any length

So, a content URI format that matches any table can be written as:

content://com.example.app.provider/*

 

And a content URI format that can match any row of data in table1 can be written as:

content://com.example.app.provider/table1/#

 

UriMatcher provides an addURI() method, which accepts three parameters, which can pass in permissions, paths and a custom code respectively.

In this way, when the match() method of UriMatcher is called, a Uri object can be passed in, and the return value is a custom code that can match the Uri object.

 

//URI string to URI object
	Uri uri = Uri.parse("content://com.example.app.provider/table1")
	
	Cursor cursor = getContentResolver().query(
		hate,
		projection,
		selection,
		selectionArgs,
		sortOrder);
	
	if (cursor != null) {
		while (cursor.moveToNext()) {
			String column1 = cursor.getString(cursor.getColumnIndex("column1"));
			int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
		}
		cursor.close();
	}
	
	//Add:
	ContentValues values = new ContentValues();
	values.put("column1", "text");
	values.put("column2", 1);
	getContentResolver().insert(uri, values);

	//Revise:
	ContentValues values = new ContentValues();
	values.put("column1", "");
	getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new	String[] {"text", "1"});	
	
	//delete:
	getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

 

Read system contacts:

The ContactsContract.CommonDataKinds.Phone class has been encapsulated for us, providing a CONTENT_URI constant, which is the result of parsing using the Uri.parse() method.

The constant corresponding to the contact name column is ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME ,

The constant corresponding to the contact phone number column is ContactsContract.CommonDataKinds.Phone.NUMBER .

 

Reading system contacts also requires declaring permissions

<uses-permission android:name="android.permission.READ_CONTACTS" />

private void readContacts() {
        Cursor cursor = null;
        try {
            // 查询联系人数据
            cursor = getContentResolver().query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null, null, null, 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);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }	

 

读取通讯录失败:

https://blog.csdn.net/njweiyukun/article/details/50044193

 

当用户手机的android系统为5.1及以下的系统,或者项目设置的targetSDK为22或者以下,那么所有的权限(普通和危险)都是在安装时候授权的,不会出现本博客所提出的问题。

但是如果你的android系统为6.0及以上并且targetSDK为23及以上,每一个危险的权限都必须在app运行时候逐一让用户点击同意或者拒绝

在 6.0版本 增强了用户的安全机制。涉及到用户的隐私以及安全的时候需要用户自己手动去授权。

 

ListViewActivity:

//第一.你需要导入最新的android-support-v4.jar包
	//第二,检测用户是否已经授权同意过该危险权限,返回true说明还没有授权或者已经拒绝,返回false说明用户已经同意了该危险权限,可以继续执行需要该权限的操作
	if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
			!= PackageManager.PERMISSION_GRANTED) {

		//第三.接着第二步返回true的情况,进行用户未授权或拒绝情况的处理
		//返回true表明用户之前已经选择过拒绝授权了;若是返回false,则表明我们还有戏,用户还没有选择过是否授权
		if (ActivityCompat.shouldShowRequestPermissionRationale(this,
				Manifest.permission.READ_CONTACTS)) {
			Toast.makeText(this, "deny for what???", Toast.LENGTH_SHORT).show();
		} else {
			Toast.makeText(this, "show the request popupwindow", Toast.LENGTH_SHORT).show();

			//第四.通过调用系统自带的弹窗询问用户是否授权
			//这时一个异步的方法,TAG_PERMISSION是我们自己定义的一个int类型常量(requestCode),用于标记我们当前的方法。调用此方法,系统会弹出一个dialog,dialog的样式我们是无法修改的
			ActivityCompat.requestPermissions(this,
					new String[]{Manifest.permission.READ_CONTACTS},1);
		}
	} else {
		Toast.makeText(this, "agreed", Toast.LENGTH_SHORT).show();
		readContacts();
	}

	
	//第五.重写请求授权的回调方法
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case 1: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
					
					//用户允许改权限,0表示允许,-1表示拒绝 PERMISSION_GRANTED = 0, PERMISSION_DENIED = -1
                    Toast.makeText(this, "allow", Toast.LENGTH_SHORT).show();
                    readContacts();
                } else {
                    Toast.makeText(this, "deny", Toast.LENGTH_SHORT).show();
                }
                return;
            }
        }

        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

 

创建自己的内容提供器

实现跨程序数据共享

 

新建一个类去继承 ContentProvider 的方式来创建一个自己的内容提供器。

ContentProvider 类中有六个抽象方法,我们在使用子类继承它的时候,需要将这六个方法全部重写。

public static final int TABLE1_DIR = 0;
	public static final int TABLE1_ITEM = 1;
	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);
	}

 

getType()方法。它是所有的内容提供器都必须提供的一个方法,用于获取 Uri 对象所对应的 MIME 类型。一个内容 URI 所对应的 MIME

字符串主要由三部分组分,Android 对这三个部分做了如下格式规定。

1. 必须以 vnd 开头。

2. 如果内容 URI 以路径结尾,则后接 android.cursor.dir/,如果内容 URI 以 id 结尾,则后接 android.cursor.item/。

3. 最后接上 vnd.<authority>.<path>。

 

所以,对于 content://com.example.app.provider/table1 这个内容 URI,它所对应的 MIME类型就可以写成:

vnd.android.cursor.dir/vnd.com.example.app.provider.table1

对于 content://com.example.app.provider/table1/1 这个内容 URI,它所对应的 MIME 类型就可以写成:

vnd.android.cursor.item/vnd. com.example.app.provider.table1

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326012643&siteId=291194637