您的位置:首页 > 移动开发 > Android开发

Android个人每天总结.doc(day04四大组件之:内容提供者ContentProvider)

2016-08-01 20:41 543 查看
作者:韩亚飞_yue31313_韩梦飞沙 QQ:313134555

day04四大组件之:内容提供者ContentProvider

Ø 内容提供者:四大组件之一ContentProvider

 

一、定义及作用:

内容提供者:四大组件之一ContentProvider

作用:

让手机中的应用独有的数据能共享

且能实现私有数据和特定的共享,权限的细化,比如让特定文件的只能读,

也就是外部应用都能访问任意应用的ContentProvider,能访问什么数据,就看里面定义了什么方法.

这样只提供方法让外部访问数据,而并不把文件暴露,提高了安全性

让外部应用能监听数据的修改

二、     怎么用?

(一)给一个应用创建内容提供者类

1.写一个类继承ContentProvider
public class SqliteProvider
extendsContentProvider {

 

   private DBFactory
helper;

   private UriMatcher
matcher;

   private static
final int
PERSON = 0;

   private  static
final int
PERSON_ID = 1;

                    

2.重写6个抽象方法
增删改查方法具本实现自已定义

里面有6个方法

① onCreate()方法:provider对象创建时运行
public boolean onCreate() {

              //获得db工具类,获得db对象

      helper = new DBFactory(getContext());

② UriMatcher工具类用于解析Uri的参数:
用UriMatcher的match(uri)方法可以解析得到Uri的参数值,返回值是之前定义的int常量:matcher.match(uri)在CURD方法中用Switch去判断match方法得到的结果,进行匹配执行.

 

      matcher = newUriMatcher(UriMatcher.NO_MATCH);

添加解析表名功能:

matcher.addURI("sql.provider.SqliteProvider",
"person", PERSON);

添加解析参数值功能:

matcher.addURI("sql.provider.SqliteProvider",
"person/#", PERSON_ID);

      return
true;

   }

③ insert方法:
这个返回值是Uri,就是把影响的行id发回去,但要uri拼接

用一个ContentUris工具类的withAppendId(uri,id);实现拼接.

 

public Uriinsert(Uri uri, ContentValues values) {

      SQLiteDatabase db = helper.getWritableDatabase();

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

用UriMatcher的match(uri)方法可以解析得到Uri的参数值

      switch (matcher.match(uri)){

      case PERSON:

        uri = ContentUris.withAppendedId(uri,

              db.insert("person",
"id", values));

        db.close();

        return uri;

      default:

        throw new IllegalArgumentException("不能识别的uri:" + uri);

      }

   }

④ delete方法:返回删除的行int
public int delete(Uri uri, Stringselection, String[] selectionArgs) {

      SQLiteDatabase db = helper.getWritableDatabase();

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

      switch (matcher.match(uri)){

      case PERSON_ID:

        long id = ContentUris.parseId(uri);

        selection = "_id=" + id;

      case PERSON:

        int i= db.delete("person", selection,selectionArgs);

        db.close();

        return i;

      default:

        throw new IllegalArgumentException("不能识别的uri:" + uri);

      }

   }

⑤ update方法:返回修该的行,int
public int update(Uri uri,ContentValues
values,String selection,

        String[]selectionArgs) {

      SQLiteDatabase db = helper.getWritableDatabase();

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

      switch (matcher.match(uri)) {

case PERSON_ID:

        long id = ContentUris.parseId(uri);

        selection = "_id=" + id;

case PERSON:

int i= db.update("person",
values, selection,selectionArgs);

        db.close();

        return i;

      default:

        throw new IllegalArgumentException("不能识别的uri:" + uri);

      }

   }

⑥ query方法:返回Cursor
注意:这里返回的是Cursor,不能关闭database,因为要传递,

public Cursorquery(Uri uri, String[] projection, String selection,

        String[]selectionArgs, String sortOrder) {

      SQLiteDatabase db = helper.getWritableDatabase();

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

      switch (matcher.match(uri)){

      case PERSON_ID:

⑦ getType:返回值是一个String 用于定义返回的事件类型.    
mimetype解释

 

3.在清单文件里注册
在application里定义<Provider name=文件位置(注意.的应用,代表当前应用包)

authorites=是ContentProvider的唯一标识(名字最好要有意义)>

 <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"
>

     

        <provider android:name=".provider.SqliteProvider"android:authorities="sql.provider.SqliteProvider"/>

 </application>

             

(二)ContentUris工具类

用于给Uri拼接一个id
       用一个ContentUris工具类的withAppendId(uri,id);实现拼接.

用于解析具体参数值返回一个long类型
 

带id的"user/#"ContentUris.parseId(Uri)

如:content://sql.provider.SqliteProvider/person/15---能得到15

4.ContentUris类用于解析Uri后的id,也可以用于给Uri追加id

ContentUris.parseId(Uri)

 

        long id = ContentUris.parseId(uri);

        selection = "_id=" + id;

      case PERSON:

        return db.query("person",
new String[] { "name",
"phone" },

              selection, null,
null, null,
null);

      default:

        throw new IllegalArgumentException("不能识别的uri:" + uri);

      }

   }

 

(三)访问内容提供者用ContentResolver

ContentResolver的CURD方法操作应用.

1.ContentResolver:用于访问内容提供者--用Context当前环境对象获取get...

其是一个ContentProvider的一个管理者类

每个应用程序是可以实现数据共享的,对于每一个应用程序程序都拥有一个contentprovider实例进行存储,而contentresolver则是用于管理所有程序的contentprovider实例,通过contentrescolver可以获得数据,插入数据等……至于getcontentrescolver()就是获取实例。。。

                            ContentResolvercr=getContentResolver();

                     2.这个类有四个方法CURD,能访问内容提供者的对应的CURD--只有查不关数据库

                            可以把helper方法定义在oncreate方法中,这样就不用在每个CURD方法中定义.

四个方法中用到两个比较重要的参数:

Uri参数:表示要访问哪个ContentProvider,需要以Content://开头,后面加上authorities定义的名字

Values参数:是ContentValues--那个map中定义sql要查询的map<String,Object>(列名,列的值).

                            注意:修改ContentProvider代码后要把那个应用重新发到手机上运行.

                      cr.insert(uri,values);

                      cr.delete(uri,where, selectionArgs);

                      cr.update(uri,values, where, selectionArgs);

                      cr.query(uri,projection, selection, selectionArgs, sortOrder);

(四)查询参数详解

table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。

projection:表示要查询列名的数组.null表示查询所有列.
columns:要查询出来的列名。相当于select语句select关键字后面的部分。
selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?”
selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
groupBy:相当于select语句group by关键字后面的部分
having:相当于select语句having关键字后面的部分
orderBy:相当于select语句order by关键字后面的部分,如:personiddesc(倒序), age asc;
limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。

(五)观察者:contentObserver

外部应用注册观察者用于监听应用数据的修改:contentObserver类

             

1.       通过getContentResolver对象注册一个ContentObserver
              有三个参数:

              Uri:这个Uri是应用清单文件中定义的Provider的authorites,但在前面要加上content://

              boolean:表示是uri是绝对

              Observer:自已定一个观察者对象

public class MainActivity
extends Activity {

  

    public
void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

       

       // 给应用中注册一个观察者ContentObserver:参数为应用的uri

        Uri uri = Uri.parse("content://com.itheima.SQLiteProvider");

MyObserver observer =new MyObserver();   

getContentResolver().registerContentObserver(uri,
true,observer );

      System.out.println("register");

    }

2.       创建一个MyObserver对象,让其作参数:具本观察细节在onChange()方法定义.
private class MyObserver
extendsContentObserver {

      public MyObserver() {

// 在主线程中创建的Handler, onChange()方法就在主线程中执行

         super(new Handler());

      }

      public void onChange(boolean selfChange) {

         System.out.println("收到数据修改的通知!");      

      }

    }

 
3.       定义ContentProvider类中哪些方法执行时让外部观察.
通过notifyChange(uri,null)方法
                     那么数据一旦修改,就会执行onChange()方法

public Uriinsert(Uri uri, ContentValues values) {

      SQLiteDatabase db = helper.getWritableDatabase();

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

不需要观察时卸载一个Resolver观察者
getContentResolver().unregisterContentObserver(observer); 

   observer = null;

(六)短信的监听案例:

       短信:mms应用是通过ContentProvider将收到的短信存入Provider.telephty中的数据库.

       注册监听,要知道应用的uri,

       用git工具,或直接去zip下载应用的源码

       短信的uri就是sms

       在应用中注册观察者就行了.

       在onChange方法中定义查询短信query方法

       查结果集注意Cursor可能有别名

       Cursor的getCount方法能获得有多少数据

       getlumnNames()方法获得所有列名.

       _id在desc Limit 1 查数据库中最后一条记录

       获得结果集后.得到想要的数据

(七)操作联系人案例---不通过事物而通过批处理appilBatch实现

       读取联系人

       主要看这数据库的三张表:

              raw_contacts:只有id 是data的外键,1对多:比如.1号联系人有三个数据,姓名,电话,邮箱....

              data:是详细数据

              mimetype:表示数据类型

       Authorites:

       要读和写联系人的权限:READ_CONTACTWRITE_CONTACT

       先查raw_contact的_id

       再通过_id查data的 data1raw_contact

       双重循环去查找

       data2里面的是电话是表示选的哪一种联系方式

       data2中的是名字中的名 data3是名字的姓.

写联系人

       向raw_contacts表中加一个id

       再通过一个id,加三个数据

appilBatch方法实现类似于事务的操作

       有两个参数:一个是Uri  一个是List里面放批量各个操作

       各个操作是一个对象,用ContentProvider的静态方法创建.

 

三、什么时候用?

当一个应用的数据需要给外部使用时,或者外部需要监听应用内部的修改

很多应用内部已定义好了,内容提供者,如电话本,短信,其实内部已经实现了内容提供者,我们看到的只是通过内容提供者访问其的数据的界面层

四、内容提供者特点:

① ContentProvider生命周期                 
1.应用安装好,就会创建好,手机开机后,第一次被访问时,被创建

2.只要创建了,只要手机没关机,就会一直存在,类似于在注册表里注册一样

3.手机关机,才会消失

4.应用里的数据都可以提供访问.不一定是数据库,在方法里自已定义就可以,但通常通是访问数据库

 

② getContext与getApplication方法的区别:都是得到当前应用的上下文环境
       getApplication:是在Activity中定义的      

       getContext是由虚拟机setContext创建的进来的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: