Android Provider

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   >  

正好 NoteEditor 这个 activity  intent-filter 满足上述条件 , 这样就找到了 NoteEditor 。于是系统加载这个类并 实例化,运行,然后就到了 NoteEditor  OnCreate 函数中(见后续文章)。

小技巧

1 ,在命令行中使用 ”adb shell” 命令进入系统中,然后 ”cd app” 进入应用程序所在目录, ”rm XXX” 就可以删除你指定的 apk ,从而去掉其 在系统顶层界面占据的图标,若两次 ”cd data” 则 可以进入应用程序使用的数据目录,你的数据可以保存在这里,例如 Notepad 就是 把其数据库放在它的 databases 目录下,名为 note_pad.db.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值