- 浏览: 240444 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
xchd:
分别在什么时候(情况下)用ThreadFactory、Exec ...
Executor线程池实例 -
mikey_5:
是不是没有写完啊
Executor线程池实例 -
xinyao:
楼主,你好,请问能给我发个源码吗,我要在一个页面能实时看到下载 ...
Android学习系列(19)--App离线下载 -
sdtzkj:
...
jasperReport 帮助文档 api -
shero_ys:
public class VrowsePicActivity ...
android handler 实现三步曲
使用ContentProvider操作数据日记本实例(1)
在上一个例子当中学习了ContentProvider,并且使用了系统中的一个联系人的ContentProvider,在本节当中,我们仍然实现类似第8章所讲的日记本的例子,只不过这次我们用ContentProvider实现,而不是直接用数据库实现。这样外界的程序就可以访问得到日记本这个应用数据。
通过这个例子可以学到。
如何实现一个ContentProvider。
理解UriMatcher的含义。
onPrepareOptionsMenu方法介绍。
具体实现步骤如下所示。
1.第一步
在Eclipse中打开ex09_2_contentProvider项目,具体操作步骤如下。
(1)新建一个项目,依次单击 File → New → Android Project项。
(2)在新建项目的对话框中,选择Create project from existing source项。
(3)单击浏览项,找到ex09_2_contentProvider项目,然后单击确定。
程序的目录结构如图8-31所示。
2.第二步
首先运行这个项目,将会看到如图8-32所示界面。
(点击查看大图)图8-31 程序的目录结构 |
(点击查看大图)图8-32 未添加任何数据的主界面 |
图8-32所示的这个界面我们在第8章的例子里已经见过。本例的主Activity仍然是一个ListActivity,而且关联的布局文件也是diary_list.xml,关于ListActivity的使用方法和详细说明可以参见第7章第6节。diary_list.xml的代码如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas. Android.com/apk/res/Android"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content">
- <ListView Android:id="@+id/Android:list"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content" />
- <TextView Android:id="@+id/Android:empty"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content" Android:text=" 您还没有开始写日记呢!单击下边的Menu按钮开始写日记吧:)" />
- </LinearLayout>
代码解释:
其中ListView的id我们必须定义成Android:id="@+id/Android:list",这样系统才可以在List Activity里引用的到。
3.第三步
和第8章的前一个日记本例子一样,日记本的数据还是存储在SQLite数据库中,但是不一样的是,在这个例子里,执行增、删、改、查操作时不是直接访问数据库,而是通过日记本程序的ContentProivder来实现。
我们先来看一下Diary这个类,这个类里边有一个内部静态类DiaryColumns,和它的名字意思一样,这个类里主要定义了日记本数据库的列表字段的名字,具体代码如下所示:
- public static final class DiaryColumns implements BaseColumns {
- private DiaryColumns() {}
- public static final Uri CONTENT_URI = Uri. parse("content://" + AUTHORITY + "/diaries");
- public static final String CONTENT_TYPE = "vnd.Android.cursor.dir/vnd.google. diary";
- public static final String CONTENT_ITEM_TYPE = "vnd.Android.cursor.item/vnd. google.diary";
- public static final String DEFAULT_SORT_ORDER = "created DESC";
- public static final String TITLE = "title";
- public static final String BODY = "body";
- public static final String CREATED = "created";
- }
代码解释:
BaseColumns 是一个接口,里边有两个变量,一个是_ID="_id",一个是_COUNT="_ count" 。在Android当中,每一个数据库表至少有一个字段,而且这个字段是_id。所以当我们构造列名的辅助类时,直接实现BaseColumns ,这样我们便默认地拥有了_id字段。
在我们的日记本的数据表里,一共有4个字段,分别是:"id"、"title"、"body"、"created"。
小知识 在Android的设计"哲学"里是鼓励开发者使用内部类的,这样不但使用方便,而且执行效率也高
。
4.第四步
现在我们来看DiaryContentProvider类,这个类继承自ContentProvider,在这个类里边实现了ContentProvider的一些接口方法,并且成为日记本的一个ContentProvider。我们现在通过学习这个类,来详细了解实现一个自定义的ContentProvider的具体步骤。
(1)继承ContentProvider.DiaryContentProvider类是继承ContentProvider类的。
(2)定义一个 public static final的Uri类型的变量,并且命名为CONTENT_URI。Diary Content Provider所能处理的Uri都是基于CONTENT_URI来构建的,需要注意的是,这个CONTENT_URI中的内容以content://开头,并且全部小写,且全局惟一。
下边是在这个例子中的一个普通URI,通过分析这个URI,可以了解content URI的构成,代码如下所示:
content://com.ex09_2_contentprovider.diarycontentprovider/diaries/1
代码解释:
第一部分是content://,这部分是一直存在的,也是不用做什么修改的。
第二部分是授权(AUTHORITY)部分,在这个例子里边就是com.ex09_2_ content provider.diarycontentprovider,授权部分是惟一的,在程序中一般是我们实现的那个Content Provider的全称,并且全都小写。这部分是和在AndroidManifest.xml文件当中的<provider Android:name ="DiaryContentProvider
Android:authorities="com.ex09_2_contentprovider. diaryconten tprovider" />部分对应的。
第三部分是请求数据的类型,例如,在这个例子当中定义的类型是diaries。当然这一部分可以是0个片段或者多个片段构成,如果Content Provider只是暴露出了一种类型的数据,那么这部分可以为空,但是如果暴露出了多种,尤其是包含子类的时候,就不能为空,例如,日记本程序里边可以暴露出来两种数据,一种是用户自己的"diaries/my",另一种是其他人的"diaries/others"。
第四部分就是"1",当然这部分是允许为空的。如果为空,表示请求全部数据;如果不为空,表示请求特定ID的数据。
(3)构建用户的数据存储系统。在这个例子当中,是将数据存储到数据库系统当中。通常是将数据存储在数据库系统中,但是也可以将数据存储在其他的地方,如文件系统等。
(4)实现ContentProvider这个抽象类的抽象方法,具体如下所示:
public boolean onCreate(),当ContentProvider生成的时候调用此方法。
public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) ,此方法返回一个Cursor 对象作为查询结果集。
public Uri insert(Uri uri, ContentValues initialValues),此方法负责往数据集当中插入一列,并返回这一列的Uri。
public int delete(Uri uri, String where, String[] whereArgs),此方法负责删除指定Uri的数据。
public int update(Uri uri, ContentValues values, String where,String[] whereArgs),此方法负责更新指定Uri的数据。
public String getType(Uri uri),返回所给Uri的MIME类型。
(5)在AndroidManifest.xml文件中增加<provider>标签,例如,在这个例子中,实现的代码为:<provider Android:name="DiaryContentProvider" Android:authorities="com.ex09_2_contentprovider. diarycontentprovider" />, 其中Android:name为我们实现的这个content provider的类名;Android: authorities为content URI的第二部分,即授权部分,代码为:"com.ex09_2_contentprovider. diarycontentprovider"。
5.第五步
继续来看DiaryContentProvider类的代码。此实例的数据是存储在数据库当中,和前面章节学过的数据例子一样,此实例中我们定义了DatabaseHelper 辅助类。这个类在第8章中有详细的讲解,这里就不再进行详细说明,具体代码如下所示:
- private static class DatabaseHelper extends SQLiteOpenHelper {
- DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + DIARY_TABLE_NAME + " ("
- + DiaryColumns._ID + " INTEGER PRIMARY KEY,"
- + DiaryColumns.TITLE + " TEXT," + DiaryColumns.BODY
- + " TEXT," + DiaryColumns.CREATED + " TEXT" + ");");
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("DROP TABLE IF EXISTS notes");
- onCreate(db);
- }
- }
代码解释:
DatabaseHelper里操作数据库的辅助类,通过这个类我们可以生成数据库,并且维护这个数据库。
在DiaryContentProvider中,我们定义了一些变量和常量,其中这些常量主要是描述数据库的信息。
- private static final String DATABASE_NAME = "database";
- private static final int DATABASE_VERSION = 1;
- private static final String DIARY_TABLE_NAME = "diary";
- private static HashMap<String, String> sDiariesProjectionMap;
- private static final int DIARIES = 1;
- private static final int DIARY_ID = 2;
- private static final UriMatcher sUriMatcher;
小知识 什么是UriMatcher?
UriMatcher是匹配Uri的一个辅助类,例如,在我们的DiaryContentProvider中的static模块中,有下边的代码:
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(Diary.AUTHORITY, "diaries", DIARIES);
sUriMatcher.addURI(Diary.AUTHORITY, "diaries/#", DIARY_ID);
代码解释:
sUriMatcher.addURI(Diary.AUTHORITY, "diaries", sUriMatcher.match(uri))表示,如果我们的Uri 是content://com.ex09_2_contentprovider.diarycontentprovider/diaries/,那么sUriMatcher.match(uri) 的返回值就是DIARIES。
sUriMatcher.addURI(Diary.AUTHORITY, "diaries/#", DIARY_ID)表示,如果我们的Uri是content://com.ex09_2_contentprovider.diarycontentprovider/diaries/id(其中后边的id是一个数字),那么sUriMatcher.match(uri)的返回值就是DIARY_ID。
通过UriMatcher类我们可以很方便地判断一个Uri的类型,特别是判断这个Uri是对单个数据的请求,还是对全部数据的请求。
6.第六步
现在我们来看一下在第四步列出来的抽象方法具体是怎么实现的。我们就从增、删、改、查的顺序说起。
(1)首先来看插入的方法:insert()。
具体实现代码如下所示:
- @Override
- public Uri insert(Uri uri, ContentValues initialValues) {
- if (sUriMatcher.match(uri) != DIARIES) {
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- ContentValues values;
- if (initialValues != null) {
- values = new ContentValues(initialValues);
- } else {
- values = new ContentValues();
- }
- if (values.containsKey(Diary.DiaryColumns.CREATED) == false) {
- values.put(Diary.DiaryColumns.CREATED, getFormateCreatedDate());
- }
- if (values.containsKey(Diary.DiaryColumns.TITLE) == false) {
- Resources r = Resources.getSystem();
- values.put(Diary.DiaryColumns.TITLE, r
- .getString(Android.R.string.untitled));
- }
- if (values.containsKey(Diary.DiaryColumns.BODY) == false) {
- values.put(Diary.DiaryColumns.BODY, "");
- }
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(DIARY_TABLE_NAME, DiaryColumns.BODY, values);
- if (rowId > 0) {
- Uri diaryUri= ContentUris.withAppendedId(
- Diary.DiaryColumns.CONTENT_URI, rowId);
- return diaryUri;
- }
- throw new SQLException("Failed to insert row into " + uri);
- }
代码解释:
首先我们通过语句sUriMatcher.match(uri) != DIARIES对传进来的Uri进行了判断,如果这个Uri不是DIARIES类型的,那么这个Uri就是一个非法的Uri。
SQLiteDatabase db = mOpenHelper.getWritableDatabase()语句负责得到一个SQLiteDatabase 的实例。
db.insert(DIARY_TABLE_NAME, DiaryColumns.BODY, values)语句负责插入一条记录到数据库中。
需要注意的是,insert()返回的是一个Uri,而不是一个记录的id,所以,我们还应该把记录的id构造成一个Uri:Uri diaryUri= ContentUris.withAppendedId(Diary.DiaryColumns.CONTENT_URI, rowId).withAppendedId()方法在下边的小知识当中详细介绍。
小知识 什么是ContentUris?
ContentUris是content URI的一个辅助类。它有两个方法很有用,具体如下所示。
public static Uri withAppendedId(Uri contentUri, long id),这个方法负责把id和contentUri连接成一个新的Uri。比如在我们这个例子当中是这么使用的:ContentUris.withAppendedId (Diary. DiaryColumns.CONTENT_URI, rowId)。如果rowId为100的话,那么现在的这个Uri的内容就是:
content://com.ex09_2_contentprovider.diarycontentprovider/diaries/100。
public static long parseId(Uri contentUri),这个方法负责把content URI 后边的id解析出来,比如现在这个content URI 是content://com.ex09_2_contentprovider.diarycontentprovider/diaries/100,那么这个函数的返回值就是100。
(2)现在来看删除方法:delete()。
具体实现代码如下所示:
- @Override
- public int delete(Uri uri, String where, String[] whereArgs) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- String rowId = uri.getPathSegments().get(1);
- return db .delete(DIARY_TABLE_NAME, DiaryColumns._ID + "=" + rowId, null);
- }
代码解释:
rowId = uri.getPathSegments().get(1)负责得到rowId的值。
getPathSegments()方法得到一个String的List,在我们例子当中uri.getPathSegments().get(1)为rowId,如果是uri.getPathSegments().get(0)那值就为"diaries"。
db.delete(DIARY_TABLE_NAME, DiaryColumns._ID + "=" + rowId, null)是标准的SQLite删除操作。第一个参数数据表的名字,第二个参数相当于SQL语句当中的where部分。
(3)更新一条数据的方法:update()。
具体实现代码如下所示:
- @Override
- public int update(Uri uri, ContentValues values, String where,
- String[] whereArgs) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- String rowId = uri.getPathSegments().get(1);
- return db.update(DIARY_TABLE_NAME, values, DiaryColumns._ID + "="
- + rowId, null);
- }
代码解释:
首先得到SQLiteDatabase 的实例,然后得到rowId,最后再调用db.update(DIARY_ TABLE_NAME, values, DiaryColumns._ID + "="+ rowId, null)语句执行更新工作。
(4)查寻一条数据的方法:query()。
具体实现代码如下所示:
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- switch (sUriMatcher.match(uri)) {
- case DIARIES:
- qb.setTables(DIARY_TABLE_NAME);
- break;
- case DIARY_ID:
- qb.setTables(DIARY_TABLE_NAME);
- qb.appendWhere(DiaryColumns._ID + "="
- + uri.getPathSegments().get(1));
- break;
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- String orderBy;
- if (TextUtils.isEmpty(sortOrder)) {
- orderBy = Diary.DiaryColumns.DEFAULT_SORT_ORDER;
- } else {
- orderBy = sortOrder;
- }
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor c = qb.query(db, projection, selection, selectionArgs, null,
- null, orderBy);
- return c;
- }
代码解释:
SQLiteQueryBuilder 是一个构造SQL查询语句的辅助类。
sUriMatcher.match(uri),根据返回值可以判断这次查询请求时,它是请求全部数据还是某个id的数据。
如果返回值是DIARIES,那么只需要执行qb.setTables(DIARY_TABLE_NAME)语句就可以了。
如果返回值是DIARY_ID,那么还需要将where部分的参数设置进去,代码为qb.appendWhere(DiaryColumns._ID + "="+ uri.getPathSegments().get(1))。
SQLiteDatabase db = mOpenHelper.getReadableDatabase(),得到一个可读的SQLiteDatabase 实例。
Cursor c = qb.query(db, projection, selection, selectionArgs, null,null, orderBy)语句,这个查询类似于一个标准的SQL查询,但是这个查询是SQLiteQueryBuilder 来发起的,而不是SQLiteDatabase 直接发起的,所以在参数方面略有不同。这个函数为 query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit)下边将各个参数介绍一下。
第一个参数为要查询的数据库实例。
第二个参数是一个字符串数组,里边的每一项代表了需要返回的列名。
第三个参数相当于SQL语句中的where部分。
第四个参数是一个字符串数组,里边的每一项依次替代在第三个参数中出现的问号(?)。
第五个参数相当于SQL语句当中的groupby部分。
第六个参数相当于SQL语句当中的having部分。
第七个参数描述是怎么进行排序。
第八个参数相当于SQL当中的limit部分,控制返回的数据的个数。
在DiaryContentProvider类里边还有两个方法,一个是getType(Uri uri),另一个是getFormateCreatedDate()。后者根据时间得到一个我们特定格式的字符串,比较简单。而前者是必须要重写的方法。下边看一下我们如何重写了getType方法,具体代码如下所示:
- public String getType(Uri uri) {
- switch (sUriMatcher.match(uri)) {
- case DIARIES:
- return DiaryColumns.CONTENT_TYPE;
- case DIARY_ID:
- return DiaryColumns.CONTENT_ITEM_TYPE;
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- }
代码解释:
此方法返回一个所给Uri的指定数据的MIME类型。它的返回值如果以vnd.Android. cursor.item开头,那么就代表这个Uri指定的是单条数据。如果是以vnd.Android.cursor.dir开头的话,那么说明这个Uri指定的是全部数据。
7.第七步
在程序主界面单击MENU键,程序运行界面如图8-33所示。
在ActivityMain中执行的代码如下所示:
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert);
- return true;
- }
代码解释:
我们给菜单(menu)添加了一项,如图8-33所示。
单击添加日记按钮后进入如图8-34所示界面。
(点击查看大图)图8-33 单击MENU键 |
(点击查看大图)图8-34 新建日记的页面 |
图8-34所示的这个页面的布局和第8章前一个日记本程序里的布局完全一样,关于布局,读者可以参看第8章日记本程序例子的讲解。
下面来看一下在ActivityDiaryEditor中,是怎么处理两种不同情况进入日记本程序界面的。一种是通过新建日记进入此界面,另一种是经过编辑日记进入此日记运行界面。下面是在ActivityDiaryEditor程序中使用的onCreate()函数,其代码如下所示:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setTheme(Android.R.style.Theme_Black);
- final Intent intent = getIntent();
- final String action = intent.getAction();
- setContentView(R.layout.diary_edit);
- mTitleText = (EditText) findViewById(R.id.title);
- mBodyText = (EditText) findViewById(R.id.body);
- confirmButton = (Button) findViewById(R.id.confirm);
- if (EDIT_DIARY_ACTION.equals(action)) {// 编辑日记
- mState = STATE_EDIT;
- mUri = intent.getData();
- mCursor = managedQuery(mUri, PROJECTION, null, null, null);
- mCursor.moveToFirst();
- String title = mCursor.getString(1);
- mTitleText.setTextKeepState(title);
- String body = mCursor.getString(2);
- mBodyText.setTextKeepState(body);
- setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
- setTitle("编辑日记");
- } else if (INSERT_DIARY_ACTION.equals(action)) {// 新建日记
- mState = STATE_INSERT;
- setTitle("新建日记");
- } else {
- Log.e(TAG, "no such action error");
- finish();
- return;
- }
- confirmButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View view) {
- if (mState == STATE_INSERT) {
- insertDiary();
- } else {
- updateDiary();
- }
- Intent mIntent = new Intent();
- setResult(RESULT_OK, mIntent);
- finish();
- }
- });
- }
代码解释:
通过getIntent()得到启动当前Activity的那个Intent。
通过 intent.getAction()得到这个intent的动作(Action)。在此操作中,当前的Activiy是通过单击先前的新建日记的按钮进来的,所以,看一下ActivityMain当中的onOptionsItemSelected()函数,了解一下动作(Action)是怎么设置的,此代码如下所示:
- Intent intent0 = new Intent(this, ActivityDiaryEditor.class);
- intent0.setAction(ActivityDiaryEditor.INSERT_DIARY_ACTION);
- intent0.setData(getIntent().getData());
- startActivity(intent0);
代码解释:
从上述代码可以看到,通过语句intent0.setAction(ActivityDiaryEditor.INSERT_ DIARY _ACTION)设置的action是ActivityDiaryEditor.INSERT_DIARY_ACTION)实现的。
在ActivityDiaryEditor中的onCreate()函数中,当动作(Action)为INSERT_DIARY_ACTION时候,我们执行mState = STATE_INSERT,也就是标记当前的状态为插入状态。
如果当前的动作(Action)是EDIT_DIARY_ACTION,那么当前就是编辑状态:mState = STATE_EDIT。
当运行程序填充数据后单击确定按钮,执行confirmButton的单击监听器当中的onClick()函数。这个函数根据不同的状态执行插入或者更新数据的操作。
按照现在的程序执行流程,单击确定按钮后,程序将执行插入操作,实现插入操作代码如下所示:
- private void insertDiary() {
- String title = mTitleText.getText().toString();
- String body = mBodyText.getText().toString();
- ContentValues values = new ContentValues();
- values.put(Diary.DiaryColumns.CREATED, DiaryContentProvider
- .getFormateCreatedDate());
- values.put(Diary.DiaryColumns.TITLE, title);
- values.put(Diary.DiaryColumns.BODY, body);
- getContentResolver().insert(Diary.DiaryColumns.CONTENT_URI, values);
- }
代码解释:
首先通过getText()方法将编辑框中的数据都读出来。
将要插入的数据都放到一个ContentValues 的实例当中。
调用getContentResolver()得到当前应用的一个ContentResolver的实例。
insert(Diary.DiaryColumns.CONTENT_URI, values)语句为ContentResolver的插入方法,这个方法有两个参数,第一个参数是数据的Uri,第二个参数是包含要插入数据的ContentValues 的实例。执行这条语句的最终会调用DiaryContentProvider中的insert()方法。
当单击确定按钮后,程序运行出现如图8-35所示的界面。
8.第八步
按方向键向下键将焦点移动到这条数据上,然后单击MENU键会出现如图8-36所示界面。
图8-36所示的这个界面和刚才讲到的单击MENU键出现的界面一样,下面看一下实现的代码,以便了解此界面是怎么生成的,具体实现代码如下所示:
(点击查看大图)图8-35 已经插入了一条数据 |
(点击查看大图)图8-36 单击MENU键界面 |
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- final boolean haveItems = getListAdapter().getCount() > 0;
- if (haveItems) {
- if (getListView().getSelectedItemId() > 0) {
- menu.removeGroup(1);
- Uri uri = ContentUris.withAppendedId(getIntent().getData(),
- getSelectedItemId());
- Intent intent = new Intent(null, uri);
- menu.add(1, MENU_ITEM_EDIT, 1, "编辑内容").setIntent(intent);
- menu.add(1, MENU_ITEM_DELETE, 1, "删除当前日记");
- }
- }else{
- menu.removeGroup(1);
- }
- return true;
- }
8.5.3 使用ContentProvider操作数据日记本实例(6)
代码解释:
当前和这个ListView相关联的ListAdapter里边元素的个数大于零的时候haveItems为真,否则为假。
menu.removeGroup(1),如果menu里边有分组为1组的子项的话,那么就先全部删除。
getIntent().getData()得到的Uri是DiaryColumns.CONTENT_URI。
通过ContentUris.withAppendedId(getIntent().getData(),getSelectedItemId())生成一个和ListView中获得焦点这一项的数据的Uri。
menu.add(1, MENU_ITEM_EDIT, 1, "编辑内容").setIntent(intent),在menu当中增加了一项"编辑内容",并且这一项和一个intent关联,这个intent主要用于携带数据,它里边携带的就是一个Uri的数据,在下边的onOptionsItemSelected()函数当中会用到。
menu.add(1, MENU_ITEM_DELETE, 1, "删除当前日记"),增加另外一项。
如果haveItems为假,也就是当前和这个ListView相关联的ListAdapter里边元素的个数为零,即数据显示在ListView上的时候,单击MENU按钮的话,如果menu当中还有第1分组的子项的话,就给删除了,实现语句为:menu.removeGroup(1)。
小知识 单击MENU按钮的时候,在Activity中回调的函数可能有两个。
第一个是onOptionsItemSelected(),这个函数只在第一次在当前应用当中单击MENU键的时候回调,以后再不回调。
第二个是onPrepareOptionsMenu(),这个函数在每次单击MENU键后显示menu的时候被系统回调,每次menu显示前都会回调此函数。我们一般根据条件改变menu显示的逻辑都放在这个函数里边。
当单击MENU键时出现3个按钮,单击其中的某一个按钮会触发Android系统回调onOptionsItemSelected()函数,此函数实现代码如下所示:
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- // 插入一条数据
- case MENU_ITEM_INSERT:
- Intent intent0 = new Intent(this, ActivityDiaryEditor.class);
- intent0.setAction(ActivityDiaryEditor.INSERT_DIARY_ACTION);
- intent0.setData(getIntent().getData());
- startActivity(intent0);
- return true;
- // 编辑当前数据内容
- case MENU_ITEM_EDIT:
- Intent intent = new Intent(this, ActivityDiaryEditor.class);
- intent.setData(item.getIntent().getData());
- intent.setAction(ActivityDiaryEditor.EDIT_DIARY_ACTION);
- startActivity(intent);
- return true;
- // 删除当前数据
- case MENU_ITEM_DELETE:
- Uri uri = ContentUris.withAppendedId(getIntent().getData(),
- getListView().getSelectedItemId());
- getContentResolver().delete(uri, null, null);
- renderListView();
- }
- return super.onOptionsItemSelected(item);
- }
代码解释:
当用户单击添加新日记按钮后,程序新建一个跳转Activity的intent0,并且设置了Action和data,这两个部分在程序跳转到ActivityDiaryEditor后会用到。
当用户单击编辑按钮后,程序也新建了一个跳转Activity的intent,并且也设置了Action和data。同样,这两部分在程序跳转到ActivityDiaryEditor后会用到。需要注意的是,通过item.getIntent().getData()得到了所需要的Uri。
当用户单击删除按钮后,程序通过ContentUris.withAppendedId(getIntent().getData(), getListView().getSelectedItemId())先得到需要删除数据的Uri,然后得到当前的ContentResolvor,然后调用它的delete方法进行删除。
删除数据后,调用renderListView()函数对ListView进行及时刷新。
相关推荐
本教程“mars—第一季android——contentProvider”聚焦于如何利用ContentProvider来实现不同应用程序之间的数据交换。 ContentProvider是Android系统提供的一种机制,允许应用程序将自己的数据公开给其他应用。...
ContentProvider提供了一种标准化的机制,使得不同的应用程序可以安全、有序地访问和共享数据,无论这些数据是存储在SQLite数据库、文件系统还是其他持久化存储中。下面我们将深入探讨ContentProvider的工作原理及其...
ContentProvider是Android系统中用于数据共享的一种机制,它可以使得应用的数据对其他应用可见并可操作。通过ContentProvider,我们可以实现跨应用的数据交换,比如联系人、日历等系统数据就是通过ContentProvider...
在Android系统中,ContentProvider是一种核心组件,它允许应用程序之间共享数据,而无需直接访问对方的内部存储。在本教程中,我们将深入探讨如何利用ContentProvider来操作文件,以及其在跨应用数据传输中的作用。 ...
在Android应用开发中,数据存储是至关重要的一个环节,它涉及到用户信息的持久化,使得应用在退出或设备重启后仍能保持之前的状态。在众多的数据存储方式中,SharedPreferences是一种轻量级的选择,尤其适用于存储小...
本实例将深入解析如何创建和使用一个简单的ContentProvider,同时涉及与数据库的操作。 一、ContentProvider基础 ContentProvider作为数据接口,使得不同的应用程序可以访问和修改其他应用的数据。Android系统中的...
(2) 提交作业应列出操作数据的Uri及数据表的字段名称; (3) 提交作业应给出自定义的CP文件的核心代码。 资源中包含自定义ContentProvider的相关实现的代码(Homework02ContentProvider),以及对应的测试代码...
SQLite提供了SQL语言来操作数据,包括创建表(CREATE TABLE)、插入数据(INSERT)、查询数据(SELECT)、更新数据(UPDATE)和删除数据(DELETE)。例如,你可以创建一个名为`Users`的表,包含`id`和`name`两个字段...
接下来,ContentProvider是Android四大组件之一,它提供了一种标准接口,使得其他应用程序可以访问和修改由ContentProvider管理的数据,无论这些数据是存储在SQLite数据库、文件系统还是网络中。要创建一个...
"Android Intent 和 ContentProvider" Android Intent 是 Android 组件之间的信使,负责在 Android 三大...Intent 负责在 Android 组件之间传递信息,而 ContentProvider 提供了一个统一的接口,用于访问和操作数据。
总结一下,本实例通过创建和使用ContentProvider,展示了在Android中如何实现数据的CRUD操作。ContentProvider是Android系统中的重要组成部分,它为不同应用间的资源共享提供了统一的接口。通过学习和实践这个实例,...
本篇文章将详细介绍如何在Android中实现一个简单的ContentProvider。 首先,理解ContentProvider的基本概念。ContentProvider是Android系统提供的一种机制,用于封装和暴露数据。它基于URI(统一资源标识符)来操作...
**ContentProvider**是Android框架的一部分,它提供了一种标准接口,使得应用程序可以访问和操作其他应用程序的数据,无论是存储在SQLite数据库、文件系统还是网络中。ContentProvider使得数据能够在不同应用程序...
在Android系统中,ContentProvider是实现应用程序间数据共享的核心组件。它允许一个应用将自己的数据集公开,让其他应用可以通过标准的ContentResolver接口进行访问。这种机制使得数据可以在多个应用之间透明地共享...
ContentProvider 提供了多种方法来操作数据,包括 insert、delete、update 和 query。这些方法可以用于对数据进行增删改查操作。例如,对于一个字典应用程序,ContentProvider 可以提供 insert 方法来插入新单词,...
在Android系统中,ContentProvider是四大组件之一,它扮演着数据共享和跨应用数据访问的角色。自定义ContentProvider允许开发者创建自己的数据存储解决方案,并与其他应用程序无缝交互。这篇博客将深入探讨如何在...
"安卓Android源码——数据口袋.zip"可能包含的是一个关于数据管理或存储的开源项目,旨在帮助开发者更好地理解和处理Android设备上的数据。这个压缩包很可能是某个开发者的个人实践、教程或者是针对Android平台的...
本示例“android 数据库 以及自定义ContentProvider demo”将带你深入理解这两个概念,并通过实践操作演示如何在Android项目中实现它们。 首先,我们来了解Android数据库。Android系统使用SQLite作为默认的轻量级...
首先,ContentProvider是Android四大组件之一,它作为数据存储和访问的桥梁,允许不同应用之间共享数据。ContentProvider基于URI(统一资源标识符)来暴露数据,并通过标准的CRUD(创建、读取、更新、删除)操作管理...
在Android应用开发中,SQLite和ContentProvider是两个非常重要的组件,它们主要用于数据存储和数据共享。SQLite是一个轻量级的数据库系统,适用于移动设备,而ContentProvider则是一种接口,允许不同应用程序之间...