android基础总结篇之八:创建及调用自己的ContentProvider

android基础总结篇之八:创建及调用自己的ContentProvider,第1张

概述今天我们来讲解一下如何创建调用自己的ContentProvider。在前面两篇文章中我们分别讲了如何读写联系人和短消息,相信大家对于ContentProvider的 *** 作方法已经有了一定程度的了解。在有些场合,除了 *** 作ContentPro

今天我们来讲解一下如何创建及调用自己的ContentProvIDer。

在前面两篇文章中我们分别讲了如何读写联系人和短消息,相信大家对于ContentProvIDer的 *** 作方法已经有了一定程度的了解。在有些场合,除了 *** 作ContentProvIDer之外,我们还有可能需要创建自己的ContentProvIDer,来提供信息共享的服务,这就要求我们很好的掌握ContentProvIDer的创建及使用技巧。下面我们就由表及里的逐步讲解每个步骤。

在正式开始实例演示之前,我们先来了解以下两个知识点:

授权:

在AndroID中,每一个ContentProvIDer都会用类似于域名的字符串来注册自己,我们成为授权(authority)。这个唯一标识的字符串是此ContentProvIDer可提供的一组URI的基础,有了这个基础,才能够向外界提供信息的共享服务。

授权是在AndroIDManifest.xml中完成的,每一个ContentProvIDer必须在此声明并授权,方式如下:

<provIDer androID:name=".someProvIDer"   androID:authoritIEs="com.your-company.someProvIDer"/> 

上面的<provIDer>元素指明了ContentProvIDer的提供者是“SomeProvIDer”这个类,并为其授权,授权的基础URI为“com.your-company.someProvIDer”。有了这个授权信息,系统可以准确的定位到具体的ContentProvIDer,从而使访问者能够获取到指定的信息。这和浏览Web页面的方式很相似,“SomeProvIDer”就像一台具体的服务器,而“com.your-company.someProvIDer”就像注册的域名,相信大家对这个概念并不陌生,由此联想一下就可以了解ContentProvIDer授权的作用了。(需要注意的是,除了AndroID内置应用程序之外,第三方程序应尽量使用以上方式的完全限定的授权名。)

MIME类型:

就像网站返回给定URL的MIME(Multipurpose Internet Mail Extensions,多用途Internet邮件扩展)类型一样(这使浏览器能够用正确的程序来查看内容),ContentProvIDer还负责返回给定URI的MIME类型。根据MIME类型规范,MIME类型包含两部分:类型和子类型。例如:text/HTML,text/CSS,text/xml等等。

AndroID也遵循类似的约定来定义MIME类型。

对于单条记录,MIME类型类似于:

vnd.androID.cursor.item/vnd.your-company.content-type

而对于记录的集合,MIME类型类似于:

vnd.androID.cursor.dir/vnd.your-company.comtent-type

其中的vnd表示这些类型和子类型具有非标准的、供应商特定的形式;content-type可以根据ContentProvIDer的功能来定,比如日记的ContentProvIDer可以为note,日程安排的ContentProvIDer可以为schedule,等等。

了解了以上两个知识点之后,我们就结合实例来演示一下具体的过程。

我们将会创建一个记录person信息的ContentProvIDer,实现对person的CRUD *** 作,访问者可以通过下面路径 *** 作我们的ContentProvIDer:


访问者可以通过“[BASE_URI]/persons”来 *** 作person集合,也可以通过“[BASE_URI]/persons/#”的形式 *** 作单个person。
我们创建一个person的ContentProvIDer需要两个步骤:

1.创建PersonProvIDer类:

我们需要继承ContentProvIDer类,实现onCreate、query、insert、update、delete和getType这几个方法。具体代码如下:

package com.scott.provIDer;  import androID.content.ContentProvIDer; import androID.content.ContentUris; import androID.content.ContentValues; import androID.content.UriMatcher; import androID.database.Cursor; import androID.database.sqlite.sqliteDatabase; import androID.net.Uri;  public class PersonProvIDer extends ContentProvIDer {    private static final UriMatcher matcher;   private DBHelper helper;   private sqliteDatabase db;      private static final String AUTHORITY = "com.scott.provIDer.PersonProvIDer";   private static final int PERSON_ALL = 0;   private static final int PERSON_ONE = 1;      public static final String CONTENT_TYPE = "vnd.androID.cursor.dir/vnd.scott.person";   public static final String CONTENT_ITEM_TYPE = "vnd.androID.cursor.item/vnd.scott.person";      //数据改变后立即重新查询   private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/persons");      static {     matcher = new UriMatcher(UriMatcher.NO_MATCH);          matcher.addURI(AUTHORITY,"persons",PERSON_ALL);  //匹配记录集合     matcher.addURI(AUTHORITY,"persons/#",PERSON_ONE); //匹配单条记录   }      @OverrIDe   public boolean onCreate() {     helper = new DBHelper(getContext());     return true;   }    @OverrIDe   public String getType(Uri uri) {     int match = matcher.match(uri);     switch (match) {     case PERSON_ALL:       return CONTENT_TYPE;     case PERSON_ONE:       return CONTENT_ITEM_TYPE;     default:       throw new IllegalArgumentException("UnkNown URI: " + uri);     }   }      @OverrIDe   public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) {     db = helper.getReadableDatabase();     int match = matcher.match(uri);     switch (match) {     case PERSON_ALL:       //doesn't need any code in my provIDer.       break;     case PERSON_ONE:       long _ID = ContentUris.parseID(uri);       selection = "_ID = ?";       selectionArgs = new String[]{String.valueOf(_ID)};       break;     default:       throw new IllegalArgumentException("UnkNown URI: " + uri);     }     return db.query("person",projection,selection,selectionArgs,null,sortOrder);   }    @OverrIDe   public Uri insert(Uri uri,ContentValues values) {     int match = matcher.match(uri);     if (match != PERSON_ALL) {       throw new IllegalArgumentException("Wrong URI: " + uri);     }     db = helper.getWritableDatabase();     if (values == null) {       values = new ContentValues();       values.put("name","no name");       values.put("age","1");       values.put("info","no info.");     }     long rowID = db.insert("person",values);     if (rowID > 0) {       notifyDataChanged();       return ContentUris.withAppendedID(uri,rowID);     }     return null;   }    @OverrIDe   public int delete(Uri uri,String[] selectionArgs) {     db = helper.getWritableDatabase();     int match = matcher.match(uri);     switch (match) {     case PERSON_ALL:       //doesn't need any code in my provIDer.       break;     case PERSON_ONE:       long _ID = ContentUris.parseID(uri);       selection = "_ID = ?";       selectionArgs = new String[]{String.valueOf(_ID)};     }     int count = db.delete("person",selectionArgs);     if (count > 0) {       notifyDataChanged();     }     return count;   }    @OverrIDe   public int update(Uri uri,ContentValues values,String[] selectionArgs) {     db = helper.getWritableDatabase();     int match = matcher.match(uri);     switch (match) {     case PERSON_ALL:       //doesn't need any code in my provIDer.       break;     case PERSON_ONE:       long _ID = ContentUris.parseID(uri);       selection = "_ID = ?";       selectionArgs = new String[]{String.valueOf(_ID)};       break;     default:       throw new IllegalArgumentException("UnkNown URI: " + uri);     }     int count = db.update("person",values,selectionArgs);     if (count > 0) {       notifyDataChanged();     }     return count;   }    //通知指定URI数据已改变   private voID notifyDataChanged() {     getContext().getContentResolver().notifyChange(NOTIFY_URI,null);       } } 

在PersonProvIDer中,我们定义了授权地址为“com.scott.provIDer.PersonProvIDer”,相信大家在前面也有所了解了。基于这个授权,我们使用了一个UriMatcher对其路径进行匹配,“[BASE_URI]/persons"和“[BASE_URI]/persons/#”这两种路径我们在上面也介绍过,分别对应记录集合和单个记录的 *** 作。在query、insert、update和delete方法中我们根据UriMatcher匹配结果来判断该URI是 *** 作记录集合还是单条记录,从而采取不同的处理方法。在getType方法中,我们会根据匹配的结果返回不同的MIME类型,这一步是不能缺少的,比如我们在query方法中有可能是查询全部集合,有可能是查询单条记录,那么我们返回的Cursor或是集合类型,或是单条记录,这个跟getType返回的MIME类型是一致的,就好像浏览网页一样,指定的url返回的信息是什么类型,那么浏览器就应该接收到对应的MIME类型。另外,我们注意到,上面代码中,在insert、update、delete方法中都调用了notifyDataChanged方法,这个方法中仅有的一步 *** 作就是通知“[BASE_URI]/persons"的访问者,数据发生改变了,应该重新加载了。

在我们的PersonProvIDer中,我们用到了Person、DBHelper类,代码如下:

package com.scott.provIDer;  public class Person {   public int _ID;   public String name;   public int age;   public String info;      public Person() {   }      public Person(String name,int age,String info) {     this.name = name;     this.age = age;     this.info = info;   } } [java] vIEw plain copypackage com.scott.provIDer;  import androID.content.Context; import androID.database.sqlite.sqliteDatabase; import androID.database.sqlite.sqliteOpenHelper;  public class DBHelper extends sqliteOpenHelper {    private static final String DATABASE_name = "provIDer.db";   private static final int DATABASE_VERSION = 1;      public DBHelper(Context context) {     super(context,DATABASE_name,DATABASE_VERSION);   }    @OverrIDe   public voID onCreate(sqliteDatabase db) {     String sql = "CREATE table IF NOT EXISTS person" +         "(_ID INTEGER PRIMARY KEY autoINCREMENT,name VARCHAR,age INTEGER,info TEXT)";     db.execsql(sql);   }    @OverrIDe   public voID onUpgrade(sqliteDatabase db,int oldVersion,int newVersion) {     db.execsql("DROP table IF EXISTS person");     onCreate(db);   } } 

最后,要想让这个ContentProvIDer生效,我们需要在AndroIDManifest.xml中声明并为其授权,如下所示:

<provIDer androID:name=".PersonProvIDer"   androID:authoritIEs="com.scott.provIDer.PersonProvIDer"   androID:multiprocess="true"/> 

其中,androID:multiprocess代表是否允许多进程 *** 作。另外我们也可以为其声明相应的权限,对应的属性是:androID:permission。

2.调用PersonProvIDer类:

完成了person的ContentProvIDer后,下面我们来看一下如何访问它。这一步我们在MainActivity中完成,看下面代码:

package com.scott.provIDer;  import java.util.ArrayList;  import androID.app.Activity; import androID.content.ContentResolver; import androID.content.ContentUris; import androID.content.ContentValues; import androID.database.Cursor; import androID.database.CursorWrapper; import androID.net.Uri; import androID.os.Bundle; import androID.os.Handler; import androID.os.Message; import androID.vIEw.VIEw; import androID.Widget.ListVIEw; import androID.Widget.SimpleCursorAdapter;   public class MainActivity extends Activity {      private ContentResolver resolver;   private ListVIEw ListVIEw;      private static final String AUTHORITY = "com.scott.provIDer.PersonProvIDer";   private static final Uri PERSON_ALL_URI = Uri.parse("content://" + AUTHORITY + "/persons");      private Handler handler = new Handler() {     public voID handleMessage(Message msg) {       //update records.       requery();     };   };      @OverrIDe   public voID onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentVIEw(R.layout.main);      resolver = getContentResolver();     ListVIEw = (ListVIEw) findVIEwByID(R.ID.ListVIEw);          //为PERSON_ALL_URI注册变化通知     getContentResolver().registerContentObserver(PERSON_ALL_URI,true,new PersonObserver(handler));   }      /**    * 初始化    * @param vIEw    */   public voID init(VIEw vIEw) {     ArrayList<Person> persons = new ArrayList<Person>();          Person person1 = new Person("Ella",22,"lively girl");     Person person2 = new Person("Jenny","beautiful girl");     Person person3 = new Person("Jessica",23,"sexy girl");     Person person4 = new Person("Kelly","hot baby");     Person person5 = new Person("Jane",25,"pretty woman");          persons.add(person1);     persons.add(person2);     persons.add(person3);     persons.add(person4);     persons.add(person5);      for (Person person : persons) {       ContentValues values = new ContentValues();       values.put("name",person.name);       values.put("age",person.age);       values.put("info",person.info);       resolver.insert(PERSON_ALL_URI,values);     }   }      /**    * 查询所有记录    * @param vIEw    */   public voID query(VIEw vIEw) { //   Uri personOneUri = ContentUris.withAppendedID(PERSON_ALL_URI,1);查询_ID为1的记录     Cursor c = resolver.query(PERSON_ALL_URI,null);          CursorWrapper cursorWrapper = new CursorWrapper(c) {              @OverrIDe       public String getString(int columnIndex) {         //将简介前加上年龄         if (getColumnname(columnIndex).equals("info")) {           int age = getInt(getColumnIndex("age"));           return age + " years old," + super.getString(columnIndex);         }         return super.getString(columnIndex);       }     };          //Cursor须含有"_ID"字段     SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,androID.R.layout.simple_List_item_2,cursorWrapper,new String[]{"name","info"},new int[]{androID.R.ID.text1,androID.R.ID.text2});     ListVIEw.setAdapter(adapter);          startManagingCursor(cursorWrapper); //管理Cursor   }      /**    * 插入一条记录    * @param vIEw    */   public voID insert(VIEw vIEw) {     Person person = new Person("Alina",26,"attractive lady");     ContentValues values = new ContentValues();     values.put("name",person.name);     values.put("age",person.age);     values.put("info",person.info);     resolver.insert(PERSON_ALL_URI,values);   }      /**    * 更新一条记录    * @param vIEw    */   public voID update(VIEw vIEw) {     Person person = new Person();     person.name = "Jane";     person.age = 30;     //将指定name的记录age字段更新为30     ContentValues values = new ContentValues();     values.put("age",person.age);     resolver.update(PERSON_ALL_URI,"name = ?",new String[]{person.name});          //将_ID为1的age更新为30 //   Uri updateUri = ContentUris.withAppendedID(PERSON_ALL_URI,1); //   resolver.update(updateUri,null);   }      /**    * 删除一条记录    * @param vIEw    */   public voID delete(VIEw vIEw) {     //删除_ID为1的记录     Uri delUri = ContentUris.withAppendedID(PERSON_ALL_URI,1);     resolver.delete(delUri,null);          //删除所有记录 //   resolver.delete(PERSON_ALL_URI,null);   }      /**    * 重新查询    */   private voID requery() {     //实际 *** 作中可以查询集合信息后Adapter.notifyDataSetChanged();     query(null);   } } 

我们看到,在上面的代码中,分别对应每一种情况进行测试,相对较为简单。我们主要讲一下registerContentObserver这一环节。

在前面的PersonProvIDer我们也提到,在数据更改后,会向指定的URI访问者发出通知,以便于更新查询记录。大家注意,仅仅是ContentProvIDer出力还不够,我们还需要在访问者中注册一个ContentObserver,才能够接收到这个通知。下面我们创建一个

PersonObserver:package com.scott.provIDer;  import androID.database.ContentObserver; import androID.os.Handler; import androID.os.Message; import androID.util.Log;  public class PersonObserver extends ContentObserver {    public static final String TAG = "PersonObserver";   private Handler handler;      public PersonObserver(Handler handler) {     super(handler);     this.handler = handler;   }      @OverrIDe   public voID onChange(boolean selfChange) {     super.onChange(selfChange);     Log.i(TAG,"data changed,try to requery.");     //向handler发送消息,更新查询记录     Message msg = new Message();     handler.sendMessage(msg);   } } 

这样一来,当ContentProvIDer发来通知之后,我们就能立即接收到,从而向handler发送一条消息,重新查询记录,使我们能够看到最新的记录信息。

最后,我们要在AndroIDManifest.xml中为MainActivity添加MIME类型过滤器,告诉系统MainActivity可以处理的信息类型:

<!-- MIME类型 --> <intent-filter>   <data androID:mimeType="vnd.androID.cursor.dir/vnd.scott.person"/> </intent-filter> <intent-filter>   <data androID:mimeType="vnd.androID.cursor.item/vnd.scott.person"/> </intent-filter> 

这样就完成了访问者的代码,我们来看一下效果:


鉴于 *** 作类型太多,我在这里就不再展示了,大家可以自己试一试。

原文链接:http://blog.csdn.net/liuhe688/article/details/7050868

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的android基础总结篇之八:创建及调用自己的ContentProvider全部内容,希望文章能够帮你解决android基础总结篇之八:创建及调用自己的ContentProvider所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147677.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存