数据存储(3)自定义内容提供器
来源:互联网 发布:战舰世界mac版国服 编辑:程序博客网 时间:2024/06/05 10:09
综述
使用系统的内容提供器先不讲,这里讨论自定义内容提供器。
因为sunshine使用了自定义内容提供器,那就要想想了,SQLite数据库完全可以满足需要了,为什么要加个内容提供器呢,
内容提供器是对SQLite的封装,也就是说,封装了之后,可以提供给别人用的,基于下面的原因:
想为其他应用提供复杂数据和文件
想让用户从我们的应用拷贝复杂数据到其他应用
想使用搜索引擎提供自定义搜索建议
天气应用的数据要提供给别人,所以用内容提供器封装一下,然后我们自己定义SQL,自己用,完全可以在DBHelper定义相关的查询语句就好,
不要内容提供器,那么下面还是继续讨论自定义内容提供器。
Designing Data Storage
下面是一些设置提供器数据结构的建议
表数据应该总是有一个“primary key”作为每行的唯一标记。可以使用这个值连接其他表中的相关行(作为foreignkey)。虽然可以为这个列使用任何名,使用BaseColumns._ID(这个表类继承BaseColumns)是最好的选择,因为连接提供器的查询结构到一个ListView要求返回的列有一个名字叫_ID.
使用Binary Large OBject (BLOB)数据类型保存不同大小或者有不同的结构的数据。比如可以使用BLOB列保存portocol buffer或者Json structure。
Designing Content URIs
A content URI is a URI that identifies data in a provider. Content URIs include the symbolic name of the entire provider (itsauthority) and a name that points to a table or file (a path). The optional id part points to an individual row in a table. Every data access method ofContentProvider
has a content URI as an argument; this allows you to determine the table, row, or file to access.
Designing an authority
Designing a path structure
Handling content URI IDs
URI匹配的的问题
我们要为查询建立匹配,首先要添加URI。private static final UriMatcher sUriMatcher = buildUriMatcher();静态方法中添加了我们需要匹配的URI,如果匹配就返回匹配值。
static UriMatcher buildUriMatcher() { // 1) The code passed into the constructor represents the code to return for the root // URI. It's common to use NO_MATCH as the code for this case. Add the constructor below. UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 2) Use the addURI function to match each of the types. Use the constants from // WeatherContract to help define the types to the UriMatcher. uriMatcher.addURI(WeatherContract.CONTENT_AUTHORITY, WeatherContract.PATH_WEATHER,WEATHER); uriMatcher.addURI(WeatherContract.CONTENT_AUTHORITY, WeatherContract.PATH_WEATHER + "/*",WEATHER_WITH_LOCATION); uriMatcher.addURI(WeatherContract.CONTENT_AUTHORITY, WeatherContract.PATH_WEATHER + "/*/#",WEATHER_WITH_LOCATION_AND_DATE); uriMatcher.addURI(WeatherContract.CONTENT_AUTHORITY, WeatherContract.PATH_LOCATION,LOCATION); // 3) Return the new matcher! return uriMatcher;}在查询中使用这个uriMatcher匹配:
@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // Here's the switch statement that, given a URI, will determine what kind of request it is, // and query the database accordingly. Cursor retCursor; switch (sUriMatcher.match(uri)) { // "weather/*/*" case WEATHER_WITH_LOCATION_AND_DATE: { retCursor = getWeatherByLocationSettingAndDate(uri, projection, sortOrder); break; } // "weather/*" case WEATHER_WITH_LOCATION: { retCursor = getWeatherByLocationSetting(uri, projection, sortOrder); break; } // "weather" case WEATHER: { retCursor = mOpenHelper.getReadableDatabase().query(WeatherContract.WeatherEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); break; } // "location" case LOCATION: { retCursor = mOpenHelper.getReadableDatabase().query(WeatherContract.LocationEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); break; } default: throw new UnsupportedOperationException("Unknown uri: " + uri); } retCursor.setNotificationUri(getContext().getContentResolver(), uri); return retCursor;}
private static final SQLiteQueryBuilder sWeatherByLocationSettingQueryBuilder;static{ sWeatherByLocationSettingQueryBuilder = new SQLiteQueryBuilder(); //This is an inner join which looks like //weather INNER JOIN location ON weather.location_id = location._id sWeatherByLocationSettingQueryBuilder.setTables( WeatherContract.WeatherEntry.TABLE_NAME + " INNER JOIN " + WeatherContract.LocationEntry.TABLE_NAME + " ON " + WeatherContract.WeatherEntry.TABLE_NAME + "." + WeatherContract.WeatherEntry.COLUMN_LOC_KEY + " = " + WeatherContract.LocationEntry.TABLE_NAME + "." + WeatherContract.LocationEntry._ID);}
然后查询的话,这样:
private Cursor getWeatherByLocationSettingAndDate( Uri uri, String[] projection, String sortOrder) { String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri); long date = WeatherContract.WeatherEntry.getDateFromUri(uri); return sWeatherByLocationSettingQueryBuilder.query(mOpenHelper.getReadableDatabase(), projection, sLocationSettingAndDaySelection, new String[]{locationSetting, Long.toString(date)}, null, null, sortOrder );}
删除和插入,更新类似吧,下面正式讲如何实现ContentProvider。
继承实现ContentProvider
query()
- query查询,上面讲了,返回一个cursor。
- Retrieve data from your provider. Use the arguments to select the table to query, the rows and columns to return, and the sort order of the result. Return the data as a
Cursor
object. insert()
- Insert a new row into your provider. Use the arguments to select the destination table and to get the column values to use. Return a content URI for the newly-inserted row.
- 插入:返回具体行的URI,使用sb.insrt返回的id
public static Uri buildWeatherUri(long id) { return ContentUris.withAppendedId(CONTENT_URI, id);}
sunshine中的例子:@Overridepublic Uri insert(Uri uri, ContentValues values) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); Uri returnUri; switch (match) { case WEATHER: { normalizeDate(values); long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, values); if ( _id > 0 ) returnUri = WeatherContract.WeatherEntry.buildWeatherUri(_id); else throw new android.database.SQLException("Failed to insert row into " + uri); break; } case LOCATION:{ long _id = db.insert(WeatherContract.LocationEntry.TABLE_NAME, null, values); if ( _id > 0 ) returnUri = WeatherContract.WeatherEntry.buildWeatherUri(_id); else throw new android.database.SQLException("Failed to insert row into " + uri); break; } default: throw new UnsupportedOperationException("Unknown uri: " + uri); } getContext().getContentResolver().notifyChange(uri, null);//通知的是传入的uri,而不是返回的uri return returnUri;}
update()
- Update existing rows in your provider. Use the arguments to select the table and rows to update and to get the updated column values. Return the number of rows updated.
- 更新:
@Overridepublic int update( Uri uri, ContentValues values, String selection, String[] selectionArgs) { // Student: This is a lot like the delete function. We return the number of rows impacted // by the update. final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); final int match = sUriMatcher.match(uri); int updateRows = 0; switch (match){ case WEATHER : updateRows = db.update(WeatherContract.WeatherEntry.TABLE_NAME, values, selection, selectionArgs); break; case LOCATION : updateRows = db.update(WeatherContract.LocationEntry.TABLE_NAME, values, selection, selectionArgs); break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } if(updateRows > 0){ getContext().getContentResolver().notifyChange(uri, null); } return updateRows;}
delete()
- Delete rows from your provider. Use the arguments to select the table and the rows to delete. Return the number of rows deleted.
@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) { // Student: Start by getting a writable database final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); int deleteRows = 0; if(selection == null) selection="1"; switch (match){ case WEATHER: deleteRows = db.delete(WeatherContract.WeatherEntry.TABLE_NAME,selection,selectionArgs); break; case LOCATION: deleteRows = db.delete(WeatherContract.LocationEntry.TABLE_NAME, selection, selectionArgs); break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); }
if(deleteRows > 0){ getContext().getContentResolver().notifyChange(uri, null);}// Student: return the actual rows deletedreturn deleteRows;
}
getType()
- Return the MIME type corresponding to a content URI. This method is described in more detail in the sectionImplementing Content Provider MIME Types.
- 表示这
- 定义的几个MIMEtype,每个表的MIME type在那个内部类中定义。
- If the URI pattern is for a single row:
android.cursor.item/
- If the URI pattern is for more than one row:
android.cursor.dir/
For example, if a provider's authority is
com.example.app.provider
, and it exposes a table namedtable1
, the MIME type for multiple rows intable1
is:vnd.android.cursor.dir/vnd.com.example.provider.table1
For a single row of
table1
, the MIME type is:vnd.android.cursor.item/vnd.com.example.provider.table1
- If the URI pattern is for a single row:
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_WEATHER;public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_WEATHER
@Overridepublic String getType(Uri uri) { // Use the Uri Matcher to determine what kind of URI this is. final int match = sUriMatcher.match(uri); switch (match) { // Student: Uncomment and fill out these two cases case WEATHER_WITH_LOCATION: case WEATHER: return WeatherContract.WeatherEntry.CONTENT_TYPE; case WEATHER_WITH_LOCATION_AND_DATE: return WeatherContract.WeatherEntry.CONTENT_ITEM_TYPE; case LOCATION: return WeatherContract.LocationEntry.CONTENT_TYPE; default: throw new UnsupportedOperationException("Unknown uri: " + uri); }}
onCreate()
- Initialize your provider. The Android system calls this method immediately after it creates your provider. Notice that your provider is not created until a
ContentResolver
object tries to access it. - 最简单,初始化DBHelper类就好了。
@Overridepublic boolean onCreate() { mOpenHelper = new WeatherDbHelper(getContext()); return true;}
创建ContentProvider注意
几个函数接收的参数:
onCreate()
which is called to initialize the providerquery(Uri, String[], String, String[], String)
which returns data to the callerinsert(Uri, ContentValues)
which inserts new data into the content providerupdate(Uri, ContentValues, String, String[])
which updates existing data in the content providerdelete(Uri, String, String[])
which deletes data from the content providergetType(Uri)
which returns the MIME type of data in the content provider
public abstract Uri insert (Uri uri,ContentValues values)
Implement this to handle requests to insert a new row. As a courtesy, call notifyChange()
after inserting. This method can be called from multiple threads, as described in Processes and Threads.
Parameters
null
.null
.Returns
- The URI for the newly inserted item
public abstract booleanonCreate ()
Implement this to initialize your content provider on startup. This method is called for all registered content providers on the application main thread at application launch time. It must not perform lengthy operations, or application startup will be delayed.
You should defer nontrivial initialization (such as opening, upgrading, and scanning databases) until the content provider is used (viaquery(Uri, String[], String, String[], String)
, insert(Uri, ContentValues)
, etc). Deferred initialization keeps application startup fast, avoids unnecessary work if the provider turns out not to be needed, and stops database errors (such as a full disk) from halting application launch.
If you use SQLite, SQLiteOpenHelper
is a helpful utility class that makes it easy to manage databases, and will automatically defer opening until first use. If you do use SQLiteOpenHelper, make sure to avoid callinggetReadableDatabase()
orgetWritableDatabase()
from this method. (Instead, overrideonOpen(SQLiteDatabase)
to initialize the database when it is first opened.)
Returns
- true if the provider was successfully loaded, false otherwise
public abstract Cursor query (Uri uri,String[] projection, String selection, String[] selectionArgs, String sortOrder)
Implement this to handle query requests from clients. This method can be called from multiple threads, as described inProcesses and Threads.
Example client call:
// Request a specific record. Cursor managedCursor = managedQuery( ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2), projection, // Which columns to return. null, // WHERE clause. null, // WHERE clause value substitution People.NAME + " ASC"); // Sort order.Example implementation:
// SQLiteQueryBuilder is a helper class that creates the // proper SQL syntax for us. SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder(); // Set the table we're querying. qBuilder.setTables(DATABASE_TABLE_NAME); // If the query ends in a specific record number, we're // being asked for a specific record, so set the // WHERE clause in our query. if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){ qBuilder.appendWhere("_id=" + uri.getPathLeafId()); } // Make the query. Cursor c = qBuilder.query(mDb, projection, selection, selectionArgs, groupBy, having, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c;
Parameters
null
all columns are included.null
then all rows are included.null
then the provider is free to define the sort order.Returns
- a Cursor or
null
.
public abstract int update (Uri uri,ContentValues values, String selection, String[] selectionArgs)
Implement this to handle requests to update one or more rows. The implementation should update all rows matching the selection to set the columns according to the provided values map. As a courtesy, callnotifyChange()
after updating. This method can be called from multiple threads, as described in Processes and Threads.
Parameters
null
.Returns
- the number of rows affected.
public abstract int delete (Uri uri,String selection, String[] selectionArgs)
Implement this to handle requests to delete one or more rows. The implementation should apply the selection clause when performing deletion, allowing the operation to affect multiple rows in a directory. As a courtesy, callnotifyChange()
after deleting. This method can be called from multiple threads, as described in Processes and Threads.
The implementation is responsible for parsing out a row ID at the end of the URI, if a specific row is being deleted. That is, the client would pass incontent://contacts/people/22
and the implementation is responsible for parsing the record number (22) when creating a SQL statement.
Parameters
Returns
- The number of rows affected.
Throws
- 数据存储(3)自定义内容提供器
- Android 内容提供器---创建内容提供器(设计数据存储)
- Android 内容提供器---创建内容提供器(设计数据存储)
- 自定义内容提供器MyProvider
- Android 内容提供器---内容提供器基础(从提供器中获取数据)
- Android 内容提供器---内容提供器基础(从提供器中获取数据) .
- Android 内容提供器---内容提供器基础(插入、更新和删除数据)
- Android 内容提供器---创建内容提供器(数据设计考虑因素)
- Android 内容提供器---创建内容提供器(Intent对象和数据访问)
- Android 内容提供器---内容提供器基础(插入、更新和删除数据)
- Android 内容提供器---创建内容提供器(数据设计考虑因素)
- Android 内容提供器---创建内容提供器(Intent对象和数据访问)
- 自定义Content Provider(内容提供器)
- 内容提供器(Content Provider)--跨程序共享数据
- 内容提供器(二 - 跨程序数据共享)
- 跨程序共享数据,内容提供器
- Android学习-内容提供器 数据共享
- 访问内容提供器(ContentProvider)提供的数据
- 动态获取UILabel的bounds
- codeforces 670C Cinema
- 2、Ajax与Java通过POST方式交互
- 欢迎使用CSDN-markdown编辑器
- Shader之学习笔记四
- 数据存储(3)自定义内容提供器
- c++第五次上机实验第二题
- sql常用命令
- fragment及fragment的通信
- c++第5次实验
- 18大经典数据挖掘算法小结
- oracle补丁p18841764相关
- 让UITableView的表头随着tableView一起滚动
- iOS滑动解锁/滑动获取验证码效果实现