博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解读Content Provider之二
阅读量:2392 次
发布时间:2019-05-10

本文共 7178 字,大约阅读时间需要 23 分钟。

修改数据
   可以通过如下方法修改被content provider保存的数据:
   1.添加新的记录;
   2.为已经存在的数据添加新值;
   3.批量更新已经存在的记录;
   4.删除记录
   所有的数据修改操作都可以通过ContentResolver的方法来完成。一些content provider在修改数据的时候要求拥有比读取数据拥有更多的权限。如果没有修改content provider数据的权限,那么ContentResolver的方法就会失效。
  添加记录
   为了添加新的记录到content provider中,首先在ContentValues对象中设置键-值对,设置的键和content provider中的列名对应,并且值的内容就是我们想为新记录设置值。然后,通过调用ContentResolver.insert()方法,并且将要处理的content provider和设置好的ContentValues键-值对作为参数传递给这个方法。这个方法将会返回新纪录的完整的URI——也就是,要操作的provider的URI加上为新记录追加的ID号。然后,你可以用这个完整的URI来进行查询操作,获得一个指向这个新记录的Cursor,并且利用这个得到的Cursor进行后续的修改记录的操作。如下例:
import android.provider.Contacts.People;	import android.content.ContentResolver;	import android.content.ContentValues; 	ContentValues values = new ContentValues();	// Add Abraham Lincoln to contacts and make him a favorite.	values.put(People.NAME, "Abraham Lincoln");	// 1 = the new contact is added to favorites	// 0 = the new contact is not added to favorites	values.put(People.STARRED, 1);	Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
  添加新的值
    如果一条记录已经存在,你可以添加新的信息到其中或者是修改已经存在的信息。例如:上面例子的下一步就是添加新的联系信息——例如一个电话号码或者是一个IM帐号再或者是邮箱的地址——到新的条目中。
    向Contacts数据库中添加新纪录的最好的方法就是追加表名到存储新纪录的URI后,然后用修改过的URI来添加新的数据值。每一个Contacts表都会暴露出一个名字作为CONTENT_DIRECTORY常量。接下来的代码是接着上面的例子,要为新创建的记录添加一个电话号码和一个邮箱地址。
Uri phoneUri = null;	Uri emailUri = null;	// Add a phone number for Abraham Lincoln.  Begin with the URI for	// the new record just returned by insert(); it ends with the _ID	// of the new record, so we don't have to add the ID ourselves.	// Then append the designation for the phone table to this URI,	// and use the resulting URI to insert the phone number.	phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);	values.clear();	values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);	values.put(People.Phones.NUMBER, "1233214567");	getContentResolver().insert(phoneUri, values);	// Now add an email address in the same way.	emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);	values.clear();	// ContactMethods.KIND is used to distinguish different kinds of	// contact methods, such as email, IM, etc. 	values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);	values.put(People.ContactMethods.DATA, "test@example.com");	values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);	getContentResolver().insert(emailUri, values);
    你可以通过调用ContentValues.put()方法通过一个byte类型的数组将少量的二进制数据加入到表中。例如:这种方法对小的图标类型的图片和短小的音频文件是十分有效的。然而,如果你有比较大的二进制数据要添加,例如一个图片文件和一首完整的歌曲,为这个要添加的数据这是一个content:URI,然后调用ContentResolver.openOutputStream()方法,并且这个文件的URI作为这个方法的参数。(这将使得content provider使用文件来存储这些数据,并且将文件文件的路径记录在这条记录的一个隐含的域中)
    在这方面,MediaStore content provider独立于图片、音频和视频文件的主要的provider,这就提供了一个便利:我们可以通过query()和managedQuery()使用一样的URI来获取二进制数据(例如:捕获到的图片)的信息,我们可以通过openInputStream()方法和刚刚获得的二进制数据的信息来获取这些二进制数据,下面的代码就显示了这个便利之处:
import android.provider.MediaStore.Images.Media;	import android.content.ContentValues;	import java.io.OutputStream;	// Save the name and description of an image in a ContentValues map.  	ContentValues values = new ContentValues(3);	values.put(Media.DISPLAY_NAME, "road_trip_1");	values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");	values.put(Media.MIME_TYPE, "image/jpeg");	// Add a new record without the bitmap, but with the values just set.	// insert() returns the URI of the new record.	Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);	// Now get a handle to the file for that record, and save the data into it.	// Here, sourceBitmap is a Bitmap object representing the file to save to the database.	try {    	OutputStream outStream = getContentResolver().openOutputStream(uri);    	sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);    	outStream.close();	} catch (Exception e) {    	Log.e(TAG, "exception while writing image", e);	}
批量更新数据
    要批量更新一组记录(例如:要将所有域的“New York”都改变为“NY”)。调用ContentResolver.update()方法,将要修改的列和数值作为参数。
删除一条记录
    要删除单个记录,使用特殊行的URI作为参数,调用ContentResolver.delete()进行删除
    要删除多个行(多条记录),使用要删除的记录的数据类型的URI和一条定义哪个行要被删除的SQL WHERE语句作为参数调用ContentResolver.delete()方法(例如:android.provider.Contacts.People.CONTENT_URI)。(注意:如果你要删除一般的类型,那就要确保包含了一条正确的WHERE语句,否则你就会删除比自己设想的要删除的记录更多的记录)。
创建一个Content Provider
    要创建一个content provider,你必须:
    1.设置一个存储数据的系统。大多数的content providers都会使用Android系统的文件存储方法或者是SQLite数据库来存储这些数据,但是你可以以任何方式存储你自己的数据。Android提供了SQLiteOpenHelper类来帮助你创建数据库和SQLiteDatabase来管理数据库。
    2.扩展ContentProvider类提供存储数据的方法
    3.在你的应用程序的ANndroidManifest.xml文件中声明自己的content provider。
扩展ContentProvider类
    你可以定义一个ContentProvider子类将自己的数据暴露给那些通过ContentResolver和Cursor对象使用这些数据的对象。原则上,这也意味着要实现6个定义在ContentProvider类中的抽象方法:
    query()
    insert()
    update()
    delete()
    getType()
    onCreate()
    query()方法必须返回一个Cursor对象,通过它可以操作请求的数据。Cursor是一个接口,但是Android提供了一些定义好的Cursor对象,可以供直接使用。例如:SQLiteCursor能够操作那些存储在SQLite数据库中数据。你可以通过SQLiteDatabase类的query()方法获得Cursor对象。这里有一些其他的Cursor实现——例如:MatrixCursor——对于那些不存储再数据库中的数据。
    因为这些ContentProvider方法可以被处于多个进程和多个线程中的ContentResolver对象调用,因此他必须以一种线程安全的方式实现。
    出于礼节,你可能希望在数据被修改的时候通过调用ContentResolver.notifyChange()来通知监听者或者用户。
    除了定义一个子类外,你仍然做如下几步来简化客户端的编程,并且使得这个类更加有效:
      1.定义一个命名为CONTENT_URI的public static final Uri。这就是代表你的content provider要处理的数据的完整的content:URI字符串。
        你必须为这个字符串常量定义一个唯一的值。最好的方式就是使用content provider完成的类名(小写).因此,对于一个Transpotation类,我们可以如下面一样定义:       
public static final Uri CONTENT_URI = Uri.parse("content://com.example.codelab.transportationprovider");
        如果这个provider包含子表,那么同样需要为每一个子表定义CONTENT_URI常量,这些子表拥有相同的权限(也就是content provider的标示符),并且这些子表仅仅由他们的路径来区分,如下面示例:
content://com.example.codelab.transportationprovider/train 	content://com.example.codelab.transportationprovider/air/domestic 	content://com.example.codelab.transportationprovider/air/international
对于content:URI的整体介绍,详看本文最后的Content URI总结部分。
      2.定义content provider要返回给客户端的列名。
      3.小心的记录每一列数据的数据类型,客户端需要这些信息来读取数据。
      4.如果你要处理一个新的数据类型,你必须定义一个新的MIME类型作为你的COntentProvider.getType()方法的返回值。
      5.如果你想添加到表中的数据太大了——一个代表大位图的文件——那么暴露数据给客户端的域必须包含一个content:URI字符串。
定义一个content provider。
    要让系统知道你自己定义的content provider,那么你应该在AndroidManifest文件中使用<provider>标签进行定义。未在这里定义的content provider对于系统来说都是不可见的。
    <provider>标签的name属性就是Conprovider子类的全名。authotities属性就是标示provider的content:URI的权限部分。例如,如果ContentProvider子类的名称是AutoInfoProvider,那么<provider>元素可能如下面这样定义:
  
  注意authorities属性忽略了content:URI的路径。例如:如果AutoINfoProvider对不同类型的autos或者不同的制造商拥有子表,   
content://com.example.autos.autoinfoprovider/honda 	content://com.example.autos.autoinfoprovider/gm/compact 	content://com.example.autos.autoinfoprovider/gm/suv
    这些路径不应该在AndroidManifest文件中声明。因为权限是对provider而言的,而不是对于路径;你的provider应该可以以自己选择的方式来解释URI的路径信息部分。
    <provider>的其他一些属性可以设置读取和改写数据的权限,提供一个展示给用户的图标和一条信息,使能和禁止provider等等。如果content provider中的数据不需要在多个进程中进行同步,那么就设置multiprocess属性为“true”。这就允许每一个客户端进程都实例化这个provider,建立必要的IPC。
Content URI总结
    下面是对于一个content URI的重要部分的概要介绍:
    A.标准的前缀,表明这些数据是被content provider持有的。这个永远不需要修改。
    B.URI所属的部分,它是用来鉴别一个content provider的。对于第三方的应用程序,这必须是类的全名(必须是小写)来确保它是唯一的。所属是定义再<provider>元素的authorities属性的:  
    C.这部分是content provider用来决定是哪些类型的数据被请求。这个可以为空,也可以有几个段那么长。如果一个content provider仅仅暴露一种类型的数据(例如:仅仅是trains类型),那么他就可以为空。如果一个content provider暴露几种类型的数据,包括子类型,那么它就有可能有几段那么长——例如:“land/bus”、“labd/train”、"sea/ship"和“sea/submarine”这四种可能的类型。

    D.被查询的特殊记录的ID。如果有,那么这个就是被请求记录的_ID值。如果请求不是对单个记录,那么这个段和斜杠都会被忽略:      

content://com.example.transportationprovider/trains

转载地址:http://nvqab.baihongyu.com/

你可能感兴趣的文章
In-Memory Column Store
查看>>
Oracle 12C ASM asmcmd amdu_extract
查看>>
Oracle AMDU- ASM Metadata Dump Utility
查看>>
C/C++程序中的profile
查看>>
一个更好的Post process结构,三角形代替四边形。
查看>>
利用Vertex shader实现Point Sprites
查看>>
图形处理器历史简介
查看>>
System Memory,AGP Memory and Video Memory in D3D.
查看>>
使用辅助库建立openGL编程环境
查看>>
使用Win32API开始openGL编程
查看>>
使用MFC开始openGL编程
查看>>
关于Gbuffer中的normal存储
查看>>
近距离观察Tone mapping.
查看>>
Physically based shading
查看>>
Color correction
查看>>
Temporal AA
查看>>
miniz compared to other real-time and high-ratio compressors
查看>>
Random number for GPU
查看>>
SSR
查看>>
引擎核心架构
查看>>