android数据共享之Content Provider(访问篇CRUD)
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);
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- 一句话锁定MySQL数据占用元凶
- android opengl 播放 yuv数据
- android setTag()/getTag()应用
- Android:listView控件,adapter,以及其他控件的组合
- Android以请求参数来获取网络数据
- Android中Activity之间的数据传递(Intent和Bundle)
- android 读取 AndroidManifest.xml 中的数据:版本号、应用名称、
- Android(安卓)数据业务框架分析