四大组件-ContentProvider

1.四大组件之Activity

2.四大组件之Service

3.四大组件之ContentProvider

4.四大组件之Broadcast Receiver

1.为什么需要ContentProvider?

大家都知道,涉及到数据的访问就要考虑到数据的安全性。怎样在保证数据的安全性的同时,又能方便的访问数据呢?

Android是基于Linux的,也继承了Linux的文件管理方式,通常每个应用都是独立的进程,也就是不同的用户。Android为每个应用程序分配了独立的用户ID和用户组ID。并且由这个应用程序创建出来的文件被赋予了相应的读写权限。其他应用程序无权访问。

这样虽然保证了数据的安全性,但是这对数据的共享给第三方造成了不便。Android系统的开发者为了解决了这个问题,设计了ContentProvider类。Content Provider很好的兼顾了二者。

2.怎样使用它?

ContentProvider(内容提供者)

1.创建UserInfoProvider类,它继承自ContentProvider并实现了ContentProvider的六个必须实现的抽象方法。

public class UserInfoProvider extends ContentProvider {    
    UserDBHelper userDBHelper;    
    public static final int USER_INFO=1;    
    public static final int PHONE=2;    
    public static final String AUTHORITIES="com.hyh.provider";//必须与AndroidManifest.xml里的android:authorities保持一致    
    public static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    
    static{        
        uriMatcher.addURI(AUTHORITIES,"user",USER_INFO);        
        uriMatcher.addURI(AUTHORITIES,"phone",PHONE);    
    }
   
    @Override    
    public boolean onCreate() {        
        Log.e("androidLog","onCreate()");        
        userDBHelper = UserDBHelper.newInstance(getContext(),"userInfo.db",null,1);        
        return false;    
    }
    
    @Nullable    
    @Override    
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        Log.e("androidLog","query()");        
        switch (uriMatcher.match(uri)){            
            case USER_INFO:                
                cursor = userDBHelper.query();                
                //监听改变通知                
                cursor.setNotificationUri(getContext().getContentResolver(),uri);                
                break;            
            case PHONE:                
                break;        
        }        
        return cursor;    
    }    
    
    @Nullable    
    @Override    
    public String getType(@NonNull Uri uri) { return null; }    

    @Nullable    
    @Override    
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {            
        Log.e("androidLog","insert()");        
        Uri newUri=uri;        
        switch (uriMatcher.match(uri)){            
            case USER_INFO:                
                long rowId=userDBHelper.insert(values);                
                newUri = ContentUris.withAppendedId(uri,rowId);                
                getContext().getContentResolver().notifyChange(uri,null);                
                break;            
            case PHONE:                
                break;        
        }        
        return newUri;    
    }
    
    @Override    
    public int delete(@NonNull Uri uri, @Nullable String selection,@Nullable String[] selectionArgs) {
        Log.e("androidLog","delete()");        
        int rowCount=0;        
        switch (uriMatcher.match(uri)){            
            case USER_INFO:                
                rowCount = userDBHelper.delete(selection,selectionArgs);                
                getContext().getContentResolver().notifyChange(uri,null);                
                break;            
            case PHONE:                
                break;        
        }        
        return rowCount;    
    }   
 
    @Override    
    public int update(@NonNull Uri uri, @Nullable ContentValues values,@Nullable String selection, @Nullable String[] selectionArgs) {        
        Log.e("androidLog","update()");        
        int rowCount=0;        
        switch (uriMatcher.match(uri)){            
            case USER_INFO:                
                rowCount = userDBHelper.update(values,selection,selectionArgs);                
                getContext().getContentResolver().notifyChange(uri,null);                
                break;            
            case PHONE:
                break;        
        }        
        return rowCount;    
    }
}
 

2.接着我们需要注册这个BookProvider,如下所示。其中android:authorities是ContentProvider的唯一标识,通过这个属性外部应用就可以访问我们的UserInfoProvider,因此android:authorities必须是唯一的,这里建议在命名的时候加上包名前缀。

<provider    
android:authorities="com.hyh.provider.test"  
android:name=".UserInfoProvider"    
android:permission="com.hyh.provider.USER"    
android:exported="true"    
android:process=":abc"    />

ContentResolver (内容解析者)

1.ContentResolver(内容解析器)和ContentProvider(内容提供器)是配套使用的,ContentProvider封装的接口要通过ContentResolver来进行使用,ContentResolver中的方法和ContentProvider要实现的方法是对应的。

ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put("name","abcdfeg");
Uri uri = Uri.parse("content://com.hyh.provider/user/10");
contentResolver.insert(uri,contentValues);
Cursor cursor = contentResolver.query(uri,null,null,null,null);
while(cursor.moveToNext()){    
    int id=cursor.getInt(0);    
    String name = cursor.getString(1);    
    Log.e("androidLog","id="+id+";name="+name);
}
Uri uri = Uri.parse("content://com.hyh.provider/user/10");
content:// 标准的前缀,用于标识该数据由ContentProvider管理,不需修改。
com.hyh.provider   URI的authority部分,用于标识该Content Provider。
user  Content Provider的路径部分,用于决定哪类数据被请求(可理解为请求哪个数据库表)。
10   被请求的特定记录的ID

ContentObserver(内容观察者)

getContext().getContentResolver().notifyChange(uri,null);

通知该uri中的内容改了表了,然后调用ContentOberver类中的onChange(boolean selfChange).

Uri uri = Uri.parse("content://sms/");
SmsContentObserver smsContentObserver = new SmsContentObserver(this,new Handler());
getContentResolver().registerContentObserver(uri,true,smsContentObserver);

class SmsContentObserver extends ContentObserver{   
    Context context;      
    public SmsContentObserver(Context context, Handler handler) {        
        super(handler);        
        this.context = context;    
    }  
  
    @Override    
    public void onChange(boolean selfChange, Uri uri) {        
        super.onChange(selfChange, uri);        
        String selection = String.format("date>%d",System.currentTimeMillis()-1000*60*60);        
        Cursor cursor = context.getContentResolver().query(uri,null,selection,null,null);        
        int columnCount = cursor.getColumnCount();        
        while(cursor.moveToNext()){            
            for (int i=0;i<columnCount;i++){                
                String columnName= cursor.getColumnName(i);                
                int type = cursor.getType(i);                
                switch (type){                    
                    case  Cursor.FIELD_TYPE_INTEGER:                        
                        int n = cursor.getInt(i);                        
                        Log.i("androidLog",columnName+"="+n);                        
                        break;                    
                    case Cursor.FIELD_TYPE_STRING:                        
                        String str = cursor.getString(i);                        
                        Log.i("androidLog",columnName+"="+str);                        
                        break;                
                }            
            }        
        }    
    }
}

3.它的原理是什么?

  • ContentProvider是通过IBinder实现通信过程的
  • getContentResolver获得到的是ApplicationContentResolver(在ContextImpt中实现的)
  • Client端ApplicationContentResolver使用ContentProviderProxy作为IBinder的Proxy(ContentProviderNative中实现)
  • Provider端通过Transport作为IBinder的实现端(ContentProvider中实现)

4.附加知识有哪些?

注意事项:

  • query、update、insert、delete方法都运行在Binder线程中。另外,onCreate运行在main线程中,也就是UI线程,所以我们不能在onCreate中做耗时操作。
  • Provider是可以不采用权限而正常使用的。
  • 如果provider中使用了权限就必须要有权限声明,否则外部程序即使引用权限也是没有用的。
  • 当xml中权限发生改变时,必须要卸载程序重新安装,否则将不会生效。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值