5、访问Content Provider

这里首先学习如何使用Content provider(包括系统提供的,比如创建一个短信收发系统)。

Content Providers的用户都不可能直接访问到Content Provider实例,只能通过ContentResolver在中间代理。客户端直接使用Content Resolver对象进行交互,Content Resolvers 方法提供了基本的持续存储数据的函数CRUD(create、retrieve、update和delete)。客户端如何获取ContentResolver的实例,可通过如下Activity的成员方法获取。不过当你访问provider时,你的应用程序应在mainfest文件请求相应的权限。

ContentResolver cr= getContext().getContentResolver();

ContentResolver提供了5个基本的对Content Provider操作的方法,后面将会深入介绍。当你创建自己的Content Provider,也就是继承了ContentProvider类时,意味着你也同时实现这5个方法(在后续章节会介绍到)。

1、final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)//Query the given URI, returning a Cursor over the result set.final Cursor managedQuery(Uri uri,String[] projection,String selection,String[]selectionArgs,String sortOrder)2、final Uri insert(Uri url, ContentValues values)//Inserts a row into a table at the given URL.3、final int  update(Uri uri, ContentValues values, String where, String[] selectionArgs)//Update row(s) in a content URI.4、final int  delete(Uri url, String where, String[] selectionArgs)//Deletes row(s) specified by a content URI.5、final String getType(Uri url)//Return the MIME type of the given content URL.


上面面提供的两种查询方法,区别在于方法managedQuery()的Cursor的生命周期由activity管理。管理的好处:activity帮你处理细节,如activity暂停时卸载,activity重新开始时重新请求。对于未被activity管理的Cursor可通过此函数让activit管理:

Activity.startManagingCursor(Cursor cursor)


6、从provider查询数据

查询主要下面两步(以User Dictinary为例)

(1)请求读取权限。在mainfest文件中配置android.permission.READ_USER_DICTIONARY

(2)自定义查询的代码。这里主要有两种处理方式:一种是显示查询的结果,另外一种是获取查询的数据。

另外当你精确查找某一个记录时,也就意味着你的里Uri需要包含其_ID值,可以通过以下两种方法追加,如下:

Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");


6.1 首先需要构造一个查询

// 指定要返回的每行的字段String[] mProjection ={    UserDictionary.Words._ID,    // Contract class constant for the _ID column name    UserDictionary.Words.WORD,   // Contract class constant for the word column name    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name};// 定义查询子句的字符串(类似Sql的where子句,但无where关键字)String mSelectionClause = null;// 初始化数组,其包含查询子句的参数值(即选择字句占位符“?”值)String[] mSelectionArgs = {""};/* * This defines a one-element String array to contain the selection argument. */String[] mSelectionArgs = {""};// 获取用户输入mSearchString = mSearchWord.getText().toString();//记得检查用户输入有效性// 为空就用null,代表查询所有的数据if (TextUtils.isEmpty(mSearchString)) {    mSelectionClause = null;    mSelectionArgs[0] = "";} else {    // 根据用户输入构造查询子句    mSelectionClause = UserDictionary.Words.WORD + " = ?";    // 用户输入的字符    mSelectionArgs[0] = mSearchString;}// 通过ContextResolver对象查询,返回Cursor对象mCursor = getContentResolver().query(    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table    mProjection,                       // The columns to return for each row    mSelectionClause                   // Either null, or the word the user entered    mSelectionArgs,                    // Either empty, or the string the user entered    mSortOrder);                       // The sort order for the returned rows// 对查询的cursor处理(空或者异常等)if (null == mCursor) {    /*     * 处理错误,此时mCursor不能使用     * call android.util.Log.e() to log this error.     *     */// If the Cursor is empty, the provider found no matches} else if (mCursor.getCount() < 1) {    /*     * 查询失败,通知用户无效查询子句     * 也有可能是你想推荐给用户的输入     */} else {    // 处理正确的查询结果}


注:使用占位符“?”,可以有效阻止恶意的SQL语句,也就是为什么间接使用mSelectionClause和mSelectionArgs来构造where语句的原因。

6.2.1显示查询结果

查询返回的是Cursor,此对象类型是列表行,因此显示Cursor内容最好凭借SimpleCursorAdapter填充器将之链接到ListView上。

(1)如果不匹配selection,provider返回空的Cursor对象,此时Cursor.getCount()为0

(2)如果发生内部错误,查询结果取决于provider(可能返回null,也可能为Exception)

// 定义从Cursor返回的字段列String[] mWordListColumns ={    UserDictionary.Words.WORD,   // Contract class constant containing the word column name    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name};// 定义返回字段将要填充的View的id,也就是int to[]int[] mWordListItems = { R.id.dictWord, R.id.locale};// Creates a new SimpleCursorAdaptermCursorAdapter = new SimpleCursorAdapter(    getApplicationContext(),               // The application's Context object    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView    mCursor,                               // The result from the query    mWordListColumns,                      // A string array of column names in the cursor    mWordListItems,                        // An integer array of view IDs in the row layout    0);                                    // Flags (usually none are needed)// Sets the adapter for the ListViewmWordList.setAdapter(mCursorAdapter);


6.2.2 从查询结果中获取数据

// 获取该字段的索引int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);/* * 如果cursor有效时才执行,可能返回null、内部错误或者Exception */if (mCursor != null) {    /*     * 在执行while语句即移动前,应首先在这里将cursor移动到下一行     *如果尝试直接查询数据,将会获得异常, 因为"row pointer" 是 -1       */    while (mCursor.moveToNext()) {        // 从字段索引中获取相应的值        newWord = mCursor.getString(index);        // 处理查询的值.        ...        // end of while loop    }} else {    //如果cursor为null或者provider扔出exception,处理}


6.3插入数据:

使用ContentResolver.insert()方法,其插入新行到provider,同时返回新加行的URI

// 定义一个新的Uri对象,其接收插入的结果Uri mNewUri;...// 定义一个对象用来暂存需插入的值ContentValues mNewValues = new ContentValues();/* * 设置插入的每一个字段的值,参数:字段名,字段值 */mNewValues.put(UserDictionary.Words.APP_ID, "example.user");mNewValues.put(UserDictionary.Words.LOCALE, "en_US");mNewValues.put(UserDictionary.Words.WORD, "insert");mNewValues.put(UserDictionary.Words.FREQUENCY, "100");mNewUri = getContentResolver().insert(    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI    mNewValues                          // the values to insert);

注:(1)由于SQLite数据库特性,这里不需要放置与字段相同类型的数据,甚至你可以不需要指定值,使用ContentValues.putNull()。

(2)主键自动增长(autoincrement),provider分配给每一行独一的_ID,用作主键。

(3)返回的新的URI如下,<id_value>就是_ID值,可利用该id对此行执行相应操作。获取此_ID值,通过ContentUris.parseId();

content://user_dictionary/words/<id_value>

6.4更新数据

客户端使用ContentResolver.update()更新数据,返回更新的行数。利用ContentValues对象暂存数据,其中只需要存储想改变的字段。若想清除,直接设置值为null就可以了。

// 定义ContentValues对象,暂存需更新的数据ContentValues mUpdateValues = new ContentValues();// 定义想更新的行的查询子句String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";String[] mSelectionArgs = {"en_%"};// 定义一变量,存储被更新的行的总数int mRowsUpdated = 0;.../* * 需更新值得存储 */mUpdateValues.putNull(UserDictionary.Words.LOCALE);mRowsUpdated = getContentResolver().update(    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI    mUpdateValues                       // the columns to update    mSelectionClause                    // the column to select on    mSelectionArgs                      // the value to compare to);


6.5删除数据

类似于查询,指定想删除行的条件,同时将返回删除的行数。执行删除操作时,应当对用户的输入采取一定错数,以防恶意输入。

// 定义删除条件String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";String[] mSelectionArgs = {"user"};// 定义变量,存储删除的行数int mRowsDeleted = 0;...// 删除mRowsDeleted = getContentResolver().delete(    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI    mSelectionClause                    // the column to select on    mSelectionArgs                      // the value to compare to);
  




更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. android opengl 播放 yuv数据
  4. android setTag()/getTag()应用
  5. Android:listView控件,adapter,以及其他控件的组合
  6. Android以请求参数来获取网络数据
  7. Android中Activity之间的数据传递(Intent和Bundle)
  8. android 读取 AndroidManifest.xml 中的数据:版本号、应用名称、
  9. Android(安卓)数据业务框架分析

随机推荐

  1. Android: 在WebView中获取网页源码
  2. xml文件的序列化示例
  3. H5判断IOS或Android
  4. 进度条、拖动条
  5. Android(安卓)Studio报错
  6. Android(安卓)实现相机功能【完整源码】
  7. nginx android app 慢网络请求超时
  8. android之自定义进度条的背景和进度的颜
  9. ionic打包apk报错问题A problem occurred
  10. android webview下载附件几种方法