ContentProvider中gettype() 和MIME类型的理解

程序入口点


类似于win32程序里的WinMain函数,Android自然也有它的程序入口点。它通过在AndroidManifest.xml文件中配置来指明,可以看到名为NotesList的activity节点下有这样一个intent-filter,其action为android.intent.action.MAIN,
Category指定为 android.intent.category.LAUNCHER,这就指明了这个activity是作为入口activity,系统查找到它后,就会创建这个activity实例来运行,若未发现就不启动(你可以把MAIN改名字试试)。


<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>

NotesList详解



就从入口点所在的activity(见图1)开始,可以看到这个activity最重要的功能就是显示日志列表。这个程序的日志都存放在Sqlite数据库中,因此需要读取出所有的日志记录并显示。

先来看两个重要的私有数据,第一个PROJECTION字段指明了“日志列表“所关注的数据库中的字段(即只需要ID和Title就可以了)。

private static final String[] PROJECTION =new String[] {
            Notes._ID, // 0
            Notes.TITLE, // 1
    };


第二个字段COLUMN_INDEX_TITLE指明title字段在数据表中的索引。
private static final int COLUMN_INDEX_TITLE = 1;
然后就进入第一个调用的函数onCreate。
        Intent intent = getIntent();
        if (intent.getData() == null) 
        {
            intent.setData(Notes.CONTENT_URI);
        }

      因为NotesList这个activity是系统调用的,此时的intent是不带数据和操作类型的,系统只是在其中指明了目标组件是Notelist,所以这里把”content:// com.google.provider.NotePad/notes”保存到intent里面,这个URI地址指明了数据库中的数据表名(参见以后的NotePadProvider类),也就是保存日志的数据表notes。
        Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null, Notes.DEFAULT_SORT_ORDER);
      然后调用managedQuery函数查询出所有的日志信息,这里第一个参数就是上面设置的” content:// com.google.provider.NotePad/notes”这个URI,即notes数据表。PROJECTION 字段指明了结果中所需要的字段,Notes.DEFAULT_SORT_ORDER 指明了结果的排序规则。实际上managedQuery并没有直接去查询数据库,而是通过Content Provider来完成实际的数据库操作,这样就实现了逻辑层和数据库层的分离。
         SimpleCursorAdapter adapter =new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor,new String[] { Notes.TITLE }, new int[] { android.R.id.text1 });
        setListAdapter(adapter);

      查询出日志列表后,构造一个CursorAdapter,并将其作为List View的数据源,从而在界面上显示出日志列表。可以看到,第二个参数是R.layout.noteslist_item,打开对应的noteslist_item.xml文件,
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:gravity="center_vertical"
    android:paddingLeft="5dip"
    android:singleLine="true"
/>

      就是用来显示一条日志记录的TextView,最后两个字段指明了实际的字段映射关系,通过这个TextView来显示一条日志记录的title字段。

处理“选择日志”事件

既然有了“日志列表”,就自然要考虑如何处理某一条日志的单击事件,这通过重载onListItemClick方法来完成,
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
        
        String action = getIntent().getAction();
        if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
            // The caller is waiting for us to return a note selected by
            // the user.  The have clicked on one, so return it now.
            setResult(RESULT_OK, new Intent().setData(uri));
        } else {
            // Launch activity to view/edit the currently selected item
            startActivity(new Intent(Intent.ACTION_EDIT, uri));
        }
    }

      首先通过”content:// com.google.provider.NotePad/notes”和日志的id 号拼接得到选中日志的真正URI,然后创建一个新的Intent,其操作类型为Intent.ACTION_EDIT,数据域指出待编辑的日志URI(这里只分析else块)。

Intent深度剖析

那么,上面这句startActivity(new Intent(Intent.ACTION_EDIT, uri))执行后会发生什么事情呢?这时候Android系统就跳出来接管了,它会根据intent中的信息找到对应的activity,在这里找到的是NoteEditor这个activity,然后创建这个activity的实例并运行。

那么,Android又是如何找到NoteEditor这个对应的activity的呢?这就是intent发挥作用的时刻了。

new  Intent(Intent.ACTION_EDIT, uri)

这里的Intent.ACTION_EDIT=” android.intent.action.EDIT”,另外通过设置断点,我们看下这里的uri值:


 

      可以看到选中的日志条目的URI是:content://com.google.provider.NotePad/notes/1

然后我们再来看下Androidmanfest.xml, 其中有这个provider
< provider  android:name ="NotePadProvider"
            android:authorities ="com.google.provider.NotePad"
/>

      发现没有?它也有com.google.provider.NotePad ,这个是content://com.google.provider.NotePad/notes/1 的一部分,同时

< activity  android:name ="NoteEditor"
            android:theme ="@android:style/Theme.Light"
            android:label ="@string/title_note"
            android:screenOrientation ="sensor"
            android:configChanges ="keyboardHidden|orientation"
>
<!--  This filter says that we can view or edit the data of
                 a single note  -->
< intent-filter  android:label ="@string/resolve_edit" >
< action  android:name ="android.intent.action.VIEW"
/>
< action  android:name ="android.intent.action.EDIT"
/>
< action  android:name ="com.android.notepad.action.EDIT_NOTE"
/>
< category  android:name ="android.intent.category.DEFAULT"
/>
< data  android:mimeType ="vnd.android.cursor.item/vnd.google.note"
/>
</ intent-filter >
<!--  This filter says that we can create a new note inside
                 of a directory of notes.  -->
< intent-filter >
< action  android:name ="android.intent.action.INSERT"
/>
< category  android:name ="android.intent.category.DEFAULT"
/>
< data  android:mimeType ="vnd.android.cursor.dir/vnd.google.note"
/>
</ intent-filter >
</ activity >

      上面第一个intent-filter 中有一个action  名为android.intent.action.EDIT ,而前面我们创建的Intent 也正好是
 

Intent.ACTION_EDIT=” android.intent.action.EDIT”,想必大家已经明白是怎么回事了吧。

下面就进入activity 选择机制了:
系统从intent 中获取道uri ,得到了content://com.google.provider.NotePad/notes/1, 去掉开始的content: 标识,得到com.google.provider.NotePad/notes/1, 然后获取前面的com.google.provider.NotePad ,然后就到Androidmanfest.xml 中找到authorities 为com.google.provider.NotePad 的provider ,这个就是后面要讲的contentprovider, 然后就加载这个content provider 。

< provider  android:name ="NotePadProvider"
            android:authorities ="com.google.provider.NotePad"
/>

在这里是NotePadProvider, 然后调用NotePadProvider 的gettype 函数,并把上述URI 传给这个函数,函数返回URI 所对应的类型(这里返回Notes.CONTENT_ITEM_TYPE ,代表一条日志记录,而CONTENT_ITEM_TYPE = " vnd.android.cursor.item/vnd.google.note " )。
   @Override
     public  String getType(Uri uri) {
         switch  (sUriMatcher.match(uri)) {
         case  NOTES:
             return  Notes.CONTENT_TYPE;
         case  NOTE_ID:
             return  Notes.CONTENT_ITEM_TYPE;
         default :
             throw
new  IllegalArgumentException( " Unknown URI  "
+  uri);
        }
}

      上面的sUriMatcher.match 是用来检测uri 是否能够被处理,而 sUriMatcher .match(uri) 返回值其实是由
        sUriMatcher  =  new  UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NotePad.AUTHORITY,  " notes " , NOTES);
        sUriMatcher.addURI(NotePad.AUTHORITY,  " notes/# " , NOTE_ID);

决定的。
 

然后系统使用获得的" vnd.android.cursor.item/vnd.google.note "和”android.intent.action.EDIT”到androidmanfest.xml中去找匹配的activity.


< intent-filter  android:label ="@string/resolve_edit" >
< action  android:name ="android.intent.action.VIEW"
/>
< action  android:name ="android.intent.action.EDIT"
/>
< action  android:name ="com.android.notepad.action.EDIT_NOTE"
/>
< category  android:name ="android.intent.category.DEFAULT"
/>
< data  android:mimeType ="vnd.android.cursor.item/vnd.google.note"
/>
</ intent-filter >

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ContentProviderAndroid平台的一种组件,用于不同应用之间共享数据。以下是一个ContentProvider的简单示例。 首先,在AndroidManifest.xml文件注册ContentProvider。示例代码如下: ``` <provider android:name=".MyContentProvider" android:authorities="com.example.myapp.provider" android:exported="true"> </provider> ``` 然后,在项目创建一个继承自ContentProvider的类。示例代码如下: ```java public class MyContentProvider extends ContentProvider { // 数据库帮助类 private MyDatabaseHelper dbHelper; // ContentProvider创建时调用 @Override public boolean onCreate() { dbHelper = new MyDatabaseHelper(getContext()); return true; } // 查询数据 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.query("my_table", projection, selection, selectionArgs, null, null, sortOrder); return cursor; } // 插入数据 @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = dbHelper.getWritableDatabase(); long id = db.insert("my_table", null, values); return ContentUris.withAppendedId(uri, id); } // 更新数据 @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int count = db.update("my_table", values, selection, selectionArgs); return count; } // 删除数据 @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int count = db.delete("my_table", selection, selectionArgs); return count; } // 返回MIME类型 @Override public String getType(Uri uri) { return "vnd.android.cursor.dir/vnd.com.example.myapp.provider.my_table"; } } ``` 在示例,query方法用于查询数据,insert方法用于插入数据,update方法用于更新数据,delete方法用于删除数据。getType方法用于返回MIME类型。 最后,在应用通过ContentResolver进行数据的增删改查操作。示例代码如下: ```java // 查询数据 Uri uri = Uri.parse("content://com.example.myapp.provider/my_table"); Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String data = cursor.getString(cursor.getColumnIndex("data")); // 处理数据 } cursor.close(); } // 插入数据 Uri uri = Uri.parse("content://com.example.myapp.provider/my_table"); ContentValues values = new ContentValues(); values.put("data", "example data"); Uri newUri = getContentResolver().insert(uri, values); // 更新数据 Uri uri = Uri.parse("content://com.example.myapp.provider/my_table"); ContentValues values = new ContentValues(); values.put("data", "new data"); String whereClause = "data=?"; String[] whereArgs = {"example data"}; int count = getContentResolver().update(uri, values, whereClause, whereArgs); // 删除数据 Uri uri = Uri.parse("content://com.example.myapp.provider/my_table"); String whereClause = "data=?"; String[] whereArgs = {"example data"}; int count = getContentResolver().delete(uri, whereClause, whereArgs); ``` 通过上述示例,你可以了解到ContentProvider的基本使用方法。它可以将数据存储在数据库,并通过ContentResolver进行增删改查操作,实现数据的共享和交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是你的春哥!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值