图11.6 Cursor接口继承关系
说明: 圆角矩形表示接口,矩形表示类。
由于这些ContentProvider方法能被位于不同进程和线程的不同ContentResolver对象调用,它们必须以线程安全的方式实现。
此外,开发人员也可以调用ContentResolver.notifyChange()方法,以便在数据修改时通知监听器。
除了定义子类自身,还应采取一些措施以简化客户端工作并让类更加易用:
(1)定义public static final Uri CONTENT_URI变量(CONTENT_URI是变量名称)。该字符串表示自定义的Content Provider处理的完整content:URI。开发人员必须为该值定义唯一的字符串。最佳的解决方式是使用Content Provider的完整类名(小写)。例如,EmployeeProvider的URI可能按如下方式定义:
public static final Uri CONTENT_URI = Uri.parse("content://com.mingrisoft.employeeprovider");
如果provider包含子表,也应该为各个子表定义URI。这些URI应该有相同的authority(因为它标识Content Provider),使用路径进行区分,例如:
content://com.mingrisoft.employeeprovider/dba
content://com.mingrisoft.employeeprovider/programmer
content://com.mingrisoft.employeeprovider/ceo
(2)定义Content Provider将返回给客户端的列名。如果开发人员使用底层数据库,这些列名通常与SQL数据库列名相同。同样,定义public static String常量,客户端用它们来指定查询中的列和其他指令。确保包含名为“_ID”的整数列来作为记录的ID值。无论记录中其他字段是否唯一,如URL,开发人员都应该包含该字段。如果打算使用SQLite数据库,_ID字段类型如下:
INTEGER PRIMARY KEY AUTOINCREMENT
(3)仔细注释每列的数据类型,客户端需要使用这些信息来读取数据。
(4)如果开发人员正在处理新数据类型,则必须定义新的MIME类型,以便在ContentProvider. getType()方法实现中返回。
(5)如果开发人员提供的byte数据太大而不能放到表格中,如bitmap文件,提供给客户端的字段应该包含content:URI字符串。
11.3.2 声明Content Provider
为了让Android系统知道开发人员编写的Content Provider,应该在应用程序的AndroidManifest.xml文件中定义
name属性的值是ContentProvider类的子类的完整名称;authorities属性是provider定义的content:URI中authority部分;ContentProvider的子类是EmployeeProvider。
android:authorities="com.mingrisoft.employeeprovider"
. . . />
注意: authorities属性删除了content:URI中的路径部分。
其他
11.4 经典范例
11.4.1 查询联系人姓名和电话
例11.2 在Eclipse中创建Android项目,名称为11.2,实现查询当前联系人应用中联系人的姓名和电话。(实例位置:光盘\TM\sl\11\11.2)
(1)修改res\layout\main.xml文件,设置背景图片和标签属性,代码如下:
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background"
android:orientation="vertical" >
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="25dp" />
(2)创建RetrieveDataActivity类,该类继承了Activity类。在onCreate()方法中获得布局文件中定义的标签,在自定义的getQueryData()方法中获得查询数据,代码如下:
public class RetrieveDataActivity extends Activity {
private String[] columns = { Contacts._ID, //获得ID值
Contacts.DISPLAY_NAME, //获得姓名
Phone.NUMBER, //获得电话
Phone.CONTACT_ID, };
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.result); //获得布局文件中的标签
tv.setText(getQueryData()); //为标签设置数据
}
private String getQueryData() {
StringBuilder sb = new StringBuilder(); //用于保存字符串