标签:完全 protect etc 函数 super tle rmi src prot
摘要:contentprivoder好像自己没有遇到过,不过通常使用 联系人,日历等等之类系统自身提供的。简略的摘抄一下网上各位的资料以作为自己记录。对 其中 getType(Uri uri)方法还是不知道具体使用方法,暂且留在这里。等后面看能不能搜集到具体使用
//UriMatcher.NO_MATCH,是一个常量,如果不匹配就返回 -1
UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
??第二步注册需要的Uri
/**
*authority:就是 contentprivoder 的authority参数,这参数必须与 androidmanifest.xml中对应privoder的authorities值一样
*path:就是完整uri中,authority后的一长串
*code:对应码
*/
//addURI 添加一个 uri,如果这个 uri匹配成功则返回匹配吗,不匹配则返回 -1
public void addURI(String authority, String path, int code)
??第三部,与已经注册的Uri进行匹配
//从以创建的uri树中去匹配传进来的uri,如果匹配成功,则返回匹配码,否则-1
public int match(Uri uri)
public static long parseId(Uri contentUri)
??这个方法是将 uri 的id解析出来,此方法返回的是一个 long型的 id。
public static Uri withAppendedId(Uri contentUri, long id)
??在指定的 uri后面添加一条 id 为指定的记录
??一个摘抄的demo
private static final String AUTHORITY = "com.smaple.hu";
private static final int PEOPLE = 1;
private static final int PEOPLE_ID = 2;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY,"people",PEOPLE);
//这里的#代表匹配任意数字,另外还可以用*来匹配任意文本
sURIMatcher.addURI(AUTHORITY,"people/#",PEOPLE_ID);
}
private void testUriMatcher() {
Uri uriExact = Uri.parse("content://"+AUTHORITY+"/people");
Log.i("info","uriExact: = "+uriExact) ;
Log.i("info","match excat = "+getType(uriExact));
Uri uriNumber = Uri.parse("content://"+AUTHORITY+"/people"+"/2");
Log.i("info","uriNumber: = "+uriNumber) ;
Log.i("info","match number = "+getType(uriNumber));
//拼接Uri
Uri newUri = ContentUris.withAppendedId(uriExact,15);
Log.i("info","newUri: = "+newUri) ;
//获取 ID
long id = ContentUris.parseId(newUri) ;
Log.i("info","ID = "+id);
Log.i("info","getPathSegments = "+newUri.getPathSegments());
}
private String getType(Uri uri){
int match = sURIMatcher.match(uri);
switch (match){
case PEOPLE:
return "vnd.android.cursor.dir/person";
case PEOPLE_ID:
return "vnd.android.cursor.item/person";
default:
return null;
}
}
??打印出来的 log信息为:
I/info: uriExact: = content://com.smaple.hu/people I/info: match excat = vnd.android.cursor.dir/person I/info: uriNumber: = content://com.smaple.hu/people/2 I/info: match number = vnd.android.cursor.item/person I/info: newUri: = content://com.smaple.hu/people/15 I/info: ID = 15 I/info: getPathSegments = [people, 15]??在UriMatcher的 math( )方法中有一个 uri.getPathSegments( ),大致的意思就是按“/”进行切分。和下面的参考资料有所差异 ??想要实现自己的 contentprovider,需要继承 “android.content.ContentProvider“ 抽象类,在继承之后必须覆写以下几个方法。
<provider
android:authorities="com.hu.smaple.provider"
android:name=".hu.provider.TestProvider"
android:exported="true"
/>
??这里有两个地方需要注意:
public class TestSQLite extends SQLiteOpenHelper {
private static final String DB_NAME = "provider.db";
private static final int DB_VERSION = 1;
private final String TABLE_NAME= "providertable";
private final String COL_ID = "_id";
private final String COL_NAME = "name" ;
private final String COL_AGE = "age" ;
private final String COL_INFO = "info" ;
public TestSQLite(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table if not exists ["+TABLE_NAME+"] "+"("+COL_ID+" integer primary key autoincrement, "
+COL_NAME+" varchar, "
+COL_AGE+" integer, "
+COL_INFO+" text)" ;
Log.i("info","create table = "+sql) ;
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE person ADD COLUMN other STRING");
}
}
??第二步,利用 contentPrivoder提供数据库的操作接口
public class TestProvider extends ContentProvider {
private static final UriMatcher sUriMatcher ;
private static final int MATCHER_TABLE = 1;
private static final String AUTHORITY = "com.hu.smaple.provider" ;
private static final String TABLE_NAME = "providertable" ;
private static final Uri CONTENT_URI_PROVIDERTABLE = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME);
private TestSQLite testSQLite ;
private static final String CONTENT_PROVIDER_TABLE = "com.hu.smaple.provider.type" ;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(AUTHORITY,TABLE_NAME,MATCHER_TABLE);
}
@Override
public boolean onCreate() {
testSQLite = new TestSQLite(getContext());
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.i("info","query uri = "+uri);
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
switch (sUriMatcher.match(uri)){
case MATCHER_TABLE:
//设置查询的表
queryBuilder.setTables(TABLE_NAME);
break;
default:
throw new IllegalArgumentException("Unknow URI: " +uri);
}
SQLiteDatabase db = testSQLite.getWritableDatabase();
Cursor c = queryBuilder.query(db,projection,selection,selectionArgs,null,null,sortOrder);
return c;
}
@Nullable
@Override
public String getType(Uri uri) {
Log.i("info","getType uri = "+uri);
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.i("info","insert uri = "+uri);
String tableName = null ;
switch (sUriMatcher.match(uri)){
case MATCHER_TABLE:tableName = TABLE_NAME ;
break;
default:
throw new IllegalArgumentException("Unknown URI: "+uri);
}
SQLiteDatabase db = testSQLite.getWritableDatabase();
long rowId = db.insert(tableName,null,values);
Uri result = ContentUris.withAppendedId(uri,rowId);
notifyChange(result);
return result;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.i("info","delete uri = "+uri);
String tableName = null ;;
switch (sUriMatcher.match(uri)){
case MATCHER_TABLE:
tableName = TABLE_NAME ;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = testSQLite.getWritableDatabase() ;
int count = db.delete(tableName,selection,selectionArgs);
// 更新数据时,通知其他ContentObserver
if(count > 0){
notifyChange(uri);
}
return count;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.i("info","update uri = "+uri);
String tableName = null;
switch (sUriMatcher.match(uri)){
case MATCHER_TABLE:
tableName = TABLE_NAME ;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = testSQLite.getWritableDatabase();
int count = db.update(tableName,values,selection,selectionArgs);
if(count > 0 ){
notifyChange(uri);
}
return count;
}
private void notifyChange(Uri uri){
Context context = getContext() ;
if(context == null) return;
ContentResolver resolver = context.getContentResolver();
if(resolver == null) return;
resolver.notifyChange(uri,null);
}
}
??注意:在其中 通过 UriMatcher、ContentUris进行对 Uri的匹配和在返回时进行对Uri拼装。
??第三步,在其它 app中通过context.getContentResolver( )使用这个共享的数据
public class MainActivity extends AppCompatActivity {
private ListView listView ;
private static final String AUTHORITY = "com.hu.smaple.provider" ;
private static final String TABLENAME = "providertable";
private static final Uri CONTENT_URI_TABLE = Uri.parse(
"content://"+AUTHORITY+"/"+TABLENAME
);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
}
public void add(View view){
ArrayList<Person> persons = new ArrayList<Person>();
Person person = new Person("Ella"+System.currentTimeMillis(), 22, "lively girl insert other app");
ContentValues cv = new ContentValues();
cv.put("name",person.name);
cv.put("age",person.age);
cv.put("info",person.info);
Uri uri = this.getContentResolver().insert(CONTENT_URI_TABLE,cv);
Log.i("info ", "insert uri =" + uri);
}
public void update(View view){
Person person = new Person() ;
person.name = "Jane";
person.age = 30 ;
person.info = "updata form other app";
ContentValues cv =new ContentValues() ;
cv.put("name",person.name);
cv.put("age",person.age);
cv.put("info",person.info);
int count = this.getContentResolver().update(CONTENT_URI_TABLE,cv,"name = ?",new String[]{"Jane"});
Log.i("info ", "update count=" + count);
}
public void delete(View view) {
int count = this.getContentResolver().delete(CONTENT_URI_TABLE,"name = ?",new String[]{"Jane"});
Log.i("info ", "delete count=" + count);
}
public void query(View view){
List<Person> persons = new ArrayList<>();
Cursor c = getContentResolver().query(CONTENT_URI_TABLE,null,null,null,null);
if(c.getCount() > 0 && null != c){
while(c.moveToNext()){
Person person = new Person() ;
person._id = c.getInt(c.getColumnIndex("_id"));
person.name = c.getString(c.getColumnIndex("name"));
person.age = c.getInt(c.getColumnIndex("age"));
person.info = c.getString(c.getColumnIndex("info"));
persons.add(person);
}
}
ArrayList<Map<String,String>> list =
new ArrayList<>() ;
for (Person person : persons) {
HashMap<String,String> map = new HashMap<>() ;
map.put("name",person.name);
map.put("info", person.age + " years old, " + person.info);
list.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2,
new String[]{"name", "info"}, new int[]{android.R.id.text1, android.R.id.text2});
listView.setAdapter(adapter);
}
}
??我在 contentprivoder的提供共享数据的界面也添加了一个 添加和查询的按钮,便于查看是否真的共享了。添加的数据为
Person person1 = new Person("Ella", 22, "lively girl");
Person person2 = new Person("Jenny", 22, "beautiful girl");
Person person3 = new Person("Jessica", 23, "sexy girl");
Person person4 = new Person("Kelly", 23, "hot baby");
Person person5 = new Person("Jane", 25, "a pretty woman");
<provider
android:authorities="com.hu.smaple.provider"
android:name=".hu.provider.TestProvider"
android:exported="true"
android:writePermission="com.hu.smaple.privoder.write"
/>
??这里我在 privoder标签中添加了一个 writePermission的权限。当然,仅仅在这里添加了是没有任何作用的。因为系统的任何权限都是要通过申请的,没有申请过的一串String代表的字符串系统根本无法识别,也就是说谁进来都会被当在外面!!!所以,要在 application标签的同级目录,写上申请 permission的代码
<permission android:name="com.hu.smaple.privoder.write"
android:label="privoder permissin"
android:protectionLevel="normal"
/>
<application
...
??这样,我们的 permission才会在 系统同中注册,在其它的 app使用<uses-permission>直接申请就好。
属性 | 含义 | 是否必须 |
name | 自定义的权限名称,通常需要遵循 Android权限定义命名方案:*.permission.* | 是 |
protectionLevel | 定义与权限相关的“风险级别”。必须是以下值之一,在确定是否授予权限时,系统可能采取不同的操作
|
是 |
permissionGroup | 可以将权限放在一个组中,但对于自定期义权限,应该避免设置此属性。如果确实希望设置此属性,可能使用以下属性代替:android.permisson-group.SYSTEM_TOOLS | 否 |
label | 可使用它对权限进行简短描述 | 否 |
description | 使用它提供对权限用途和所保护对象的更有用的描述 | 否 |
icon | 权限可以与资源目录以外的图标相关联 ( 比如@drawable/myicon) | 否 |
??进行一写入操作就错误,log出的错误为:
java.lang.SecurityException: Permission Denial: writing com.hu.smaple.hu.provider.TestProvider uri content://com.hu.smaple.provider/providertable from pid=10690, uid=10102 requires com.hu.smaple.write, or grantUriPermission()
??当我们Androidmanifest.xml中像申请系统权限一样的方式把 writepermission权限申请一下,就又能愉快的玩耍了
<uses-permission android:name="com.hu.smaple.privoder.write"/>
??对于数据变化时候监听,打印log测试后我在一个app里面使用注册 ContentObserver 实现类后,只用在自身 app,数据变化的时候,才会调用 onChange( )方法。
??在使用ContentProvider时由于我们无法得知数据的实际来源和数据操作的复杂度,如可能是读磁盘甚至是读网络,亦或有比较耗时的计算,所以我们无法保障数据返回的时间。因此就有必要使用异步查询来将耗时操作切换至后台线程,并在执行完成后切回到UI线程。对于直接使用Thread/Runnable - Handler这种情况实际上考虑的事情非常多,最关键的是写出来不优雅,用起来难受。我们可以使用Loader/LoaderManager和AsyncQuery
标签:完全 protect etc 函数 super tle rmi src prot
原文地址:http://blog.csdn.net/guyuelin123/article/details/64441319