正文  UI设计 > Launcher >

Android Launcher开发之LiveFolder(实时文件夹)详解

实时文件夹概述:实时文件夹是在SDK1.5中引入的,支持开发人员在设备的默认打开屏幕(我们将其称为设备的主页)上公开 ContentProvider,如联系人信息、笔记和媒体。将ContentProvider(比如Android的 contactsC......

实时文件夹概述:

实时文件夹是在SDK1.5中引入的,支持开发人员在设备的默认打开屏幕(我们将其称为设备的主页)上公开 ContentProvider,如联系人信息、笔记和媒体。将ContentProvider(比如Android的 contactsContentProvider)在主页上公开为活动文件夹之后,在联系人数据库中添加、删除或修改联系人时,此实时文件夹能够刷新自身所包含的内容。

 

Android中的实时文件夹对ContentProvider的作用就相当于RSS阅读器对发布网站的作用。ContentProvider也是类似于根据URI提供信息的网站。随着网站的迅速增加,每个网站都会以独特的方式发布自己的信息,这就需要集中多个网站的信息,以便用户可以通过单一阅读器了解最新发展动态。为此,RSS应运而生。RSS强制在不同的信息集之间提供一种通用的使用模式。有了通用模式,你只需设计一次阅读器,就可以使用它阅读任何内容,只要该内容具有统一的结构即可。

    实时文件夹在概念上也没有什么不同。就像 RSS阅读器为所发布的网站内容提桶通用的接口一样,实时文件夹也为Android中的 ContentProvider定义一种通用接口。只要 ContentProvider遵守此协议,Android就能够在设备的主页上创建活动文件夹图标来表示该 ContentProvider。当用户单击此活动文件夹图标时,系统将联系 ContentProvider。ContentProvider 应该会返回一个游标。根据活动文件夹契约,此游标必须具有一组预定义的列。此游标通过  ListView 或 GridView直观地显示出来。

   android实时文件夹   android LiveFolder, 为什么说它是实时的,因为它可以根据我们后台数据库的变化更新自身 更新UI 这样无论什么时候显示的内容都是最新的。 比如 我们删除了一条联系人信息,我们的 Live Foler马上也会 更新。是马上 而且你也不用做任何操作 它自己会更新

 

用户如何使用活动文件夹:

(1) 打开android模拟器 来到主页 (默认屏幕)

(2) 转到主页的上下文菜单。通过在主页的空白处进行长单击(按住不撒手 大约2秒钟),就可以看到上下文菜单了。

(3) 找到一个名为 Folders(中文名就叫文件夹) 的上下文菜单选项,单击可以查看可能可用的活动文件夹。

(4) 从列表中选择并单击希望在主页上公开的活动文件夹名称。这会在主页上创建一个图标来表示所选的活动文件夹。

(5) 单击在第4步中设置的活动文件夹图标,调出 ListView或GridView中的信息(该活动文件夹表示的数据)行。

(6) 单击一行以调用知道如何显示该行数据的应用程序。

(7) 使用该应用程序显示的更多菜单选项查看或操作目标选项。也可以使用应用程序的菜单选项创建它支持的任何新项。

(8) 请注意,活动文件夹显示区域会自动反应对一个或多个项所做的更改。

 

Eg:

 

通过代码构建实时文件夹(LiveFolder):

 

要构建活动文件夹,需要两样东西:一个活动和一个专门的ContentProvider。Android使用此活动的 “ 标签” 来填充可用活动文件夹列表。Android还调用此活动来获得一个URI,这个URI将被调用来显示一组行。

  活动提供的URI 应该指向负责返回行的专门的ContentProvider。该ContentProvider通过一个定义良好的游标返回这些行。我们要求游标 “定义良好”, 因为游标应该具有一组已知的预定义列名称。

 

Eg:

1. AndroidManifest.xml

 

 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="xiaohang.zhimeng" android:versionCode="1" android:versionName="1.0">  
  4.     <uses-sdk android:minSdkVersion="10" />  
  5.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  6.         <activity android:name=".SimpleActivity" android:label="@string/app_name">  
  7.             <intent-filter>  
  8.                 <action android:name="android.intent.action.MAIN" />  
  9.                 <category android:name="android.intent.category.LAUNCHER" />  
  10.             </intent-filter>  
  11.         </activity>  
  12.         <!-- LIVE FOLDERS -->  
  13.         <activity android:name=".AllContactsLiveFolderCreatorActivity"  
  14.             android:label="My live folder" android:icon="@drawable/contacts">  
  15.             <intent-filter>  
  16.                 <span style="color:#FF0000;"><action android:name="android.intent.action.CREATE_LIVE_FOLDER" /></span>  
  17.                 <category android:name="android.intent.category.DEFAULT" />  
  18.             </intent-filter>  
  19.         </activity>  
  20.         <provider android:authorities="com.ai.livefolders.contacts"  
  21.             android:multiprocess="true" android:name=".MyContactsProvider" />  
  22.     </application>  
  23.     <span style="color:#FF0000;"><uses-permission android:name="android.permission.READ_CONTACTS" /></span>  
  24. </manifest>  

 

2. 根据活动文件夹协议,CREATE_LIVE_FOLDER Intent 允许主页的上下文菜单将
AllContactsLiveFolderCreatorActivity 显示为一个标题为 “My live foler” 的选项。单击此菜单选项将在主页上创建一个图标。AllContactsLiveFolderCreatorActivity 负责定义此图标,其中将包含一个图像和一个标签。在本例子中,AllContactsLiveFolderCreatorActivity 中的代码将此标签指定为 Contacts LF。下面让我们看看创建活动文件夹的类AllContactsLiveFolderCreatorActivity:

 

 

 
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.net.Uri;  
  6. import android.os.Bundle;  
  7. import android.provider.LiveFolders;  
  8.   
  9. public class AllContactsLiveFolderCreatorActivity extends Activity {  
  10.   
  11.     @Override  
  12.     protected void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.   
  15.         final Intent intent = getIntent();  
  16.         final String action = intent.getAction();  
  17.         System.out.println("action is " + action);  
  18.         if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {  
  19.             // 设置本Activity返回的结果  
  20.             setResult(  
  21.                     RESULT_OK,  
  22.                     createLiveFolder(MyContactsProvider.CONTACTS_URI,  
  23.                             "Contacts LF", R.drawable.contacts));  
  24.         } else {  
  25.             setResult(RESULT_CANCELED);  
  26.         }  
  27.         finish();  
  28.     }  
  29.   
  30.     private Intent createLiveFolder(Uri uri, String name, int icon) {  
  31.         final Intent intent = new Intent();  
  32.         intent.setData(uri);  
  33.         // 设置LiveFolder 的Name(这个名字是显示在手机的主页上的)  
  34.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);  
  35.         // 设置LiveFolder 的图标  
  36.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,  
  37.                 Intent.ShortcutIconResource.fromContext(this, icon));  
  38.         // 指定LiveFolder 显示的模式 这里用List以列表的形式显示  
  39.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,  
  40.                 LiveFolders.DISPLAY_MODE_LIST);  
  41.         return intent;  
  42.     }  
  43. }  


 

AllContactsLiveFolderCreatorActivity 类只有一个功能:担当活动文件夹的生成程序或创建程序。可以将它视为活动文件夹的模板。每次单击此活动(通过主页上下文菜单的Folers选项)时,它都会在主页上生成一个活动文件夹。此活动告诉调用方(在这个例子中为主页或LiveFolder框架) 活动文件夹名称、为活动文件夹图标使用的图像、提供可用数据的 URI,以及显示模式 (列表或网格)。然后,活动文件夹框架负责在主页上创建活动文件夹的图标。

 

createLiveFoler() 方法主要设置调用它的Intent的值。当此 Intent返回到调用方时,调用方将知道以下信息。

  活动文件夹的名称
   活动文件夹所使用的图标
   显示模式:列表或网格
   数据或为数据调用的内容URI

3.MyContactsProvider: 当用户单击活动文件夹的图标时,系统将调用 URI 来检索数据。此 URI 所标识的 ContentProvider提供了标准化的游标:

 

 
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.content.ContentProvider;  
  4. import android.content.ContentValues;  
  5. import android.content.UriMatcher;  
  6. import android.database.Cursor;  
  7. import android.database.MatrixCursor;  
  8. import android.net.Uri;  
  9. import android.provider.BaseColumns;  
  10. import android.provider.ContactsContract;  
  11. import android.provider.LiveFolders;  
  12. import android.util.Log;  
  13.   
  14. public class MyContactsProvider extends ContentProvider {  
  15.   
  16.     public static final String AUTHORITY = "com.ai.livefolders.contacts";  
  17.   
  18.     // Uri that goes as input to the live-folder creation  
  19.     public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITY  
  20.             + "/contacts");  
  21.   
  22.     // To distinguish this URI  
  23.     private static final int TYPE_MY_URI = 0;  
  24.     private static final UriMatcher URI_MATCHER;  
  25.     static {  
  26.         URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);  
  27.         URI_MATCHER.addURI(AUTHORITY, "contacts", TYPE_MY_URI);  
  28.     }  
  29.   
  30.     @Override  
  31.     public boolean onCreate() {  
  32.         return true;  
  33.     }  
  34.   
  35.     @Override  
  36.     public int bulkInsert(Uri uri, ContentValues[] values) {  
  37.         return 0;  
  38.     }  
  39.   
  40.     // Set of columns needed by a live folder  
  41.     // This is the live-folder contract  
  42.     private static final String[] CURSOR_COLUMNS = new String[] {  
  43.             BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION,  
  44.             LiveFolders.INTENT, LiveFolders.ICON_PACKAGE,  
  45.             LiveFolders.ICON_RESOURCE };  
  46.   
  47.     // In case there are no rows  
  48.     // use this stand-in as an error message  
  49.     // Notice it has the same set of columns of a live folder  
  50.     private static final String[] CURSOR_ERROR_COLUMNS = new String[] {  
  51.             BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION };  
  52.   
  53.     // The error message row  
  54.     private static final Object[] ERROR_MESSAGE_ROW = new Object[] { -1, // id  
  55.             "No contacts found", // name  
  56.             "Check your contacts database" // description  
  57.     };  
  58.   
  59.     // The error cursor to use  
  60.     private static MatrixCursor sErrorCursor = new MatrixCursor(  
  61.             CURSOR_ERROR_COLUMNS);  
  62.     static {  
  63.         // 为 CURSOR_ERROR_COLUMNS 添加给定的列值  
  64.         sErrorCursor.addRow(ERROR_MESSAGE_ROW);  
  65.     }  
  66.   
  67.     // Columns to be retrieved from the contacts database  
  68.     private static final String[] CONTACTS_COLUMN_NAMES = new String[] {  
  69.             ContactsContract.PhoneLookup._ID,  
  70.             ContactsContract.PhoneLookup.DISPLAY_NAME,  
  71.             ContactsContract.PhoneLookup.TIMES_CONTACTED,  
  72.             ContactsContract.PhoneLookup.STARRED,  
  73.             ContactsContract.PhoneLookup.PHOTO_ID };  
  74.   
  75.     @Override  
  76.     public Cursor query(Uri uri, String[] projection, String selection,  
  77.             String[] selectionArgs, String sortOrder) {  
  78.         // Figure out the uri and return error if not matching  
  79.         int type = URI_MATCHER.match(uri);  
  80.         if (type == UriMatcher.NO_MATCH) {  
  81.             // 如果URI 匹配出错则返回错误信息  
  82.             return sErrorCursor;  
  83.         }  
  84.   
  85.         Log.i("ss", "query called");  
  86.   
  87.         try {  
  88.             // 调用 loadNewData方法进行查询 返回 匹配好的MatrixCursor对象  
  89.             MatrixCursor mc = loadNewData(this);  
  90.             // setNotificationUri方法用来指定一个Uri以观察它的变化  
  91.             // 参数一:需要一个ContentResolver对象,从上下文对象获得  
  92.             // 参数二:要监视的URI  
  93.             mc.setNotificationUri(getContext().getContentResolver(),  
  94.                     Uri.parse("content://com.android.contacts/contacts/"));  
  95.             MyCursor wmc = new MyCursor(mc, this);  
  96.             return wmc;  
  97.         } catch (Exception e) {  
  98.             System.out.println("Print yi chang ");  
  99.             // 返回我们的错误对象  
  100.             return sErrorCursor;  
  101.         }  
  102.   
  103.     }  
  104.   
  105.     public static MatrixCursor loadNewData(ContentProvider cp) {  
  106.         //  
  107.         MatrixCursor mc = new MatrixCursor(CURSOR_COLUMNS);  
  108.         Cursor allContacts = null;  
  109.         try {  
  110.             // 说一下query方法的参数  
  111.             /* 
  112.              * 参数一:要查询的URI 我们查询的完整URI 为"content://com.android.contacts/contacts" 
  113.              * 也就是所有的联系人参数二:都要查询那些列 上边我们已经定义好参数三:本质上就是一个WHERE子句,它以SQL 
  114.              * WHERE子句(不包含WHERE本身) 的格式声明要返回的行 传递null将返回给定URI 的所有行 
  115.              * 参数四:用来替换where子句中的?号参数五:指定排序的方式 
  116.              */  
  117.             allContacts = cp  
  118.                     .getContext()  
  119.                     .getContentResolver()  
  120.                     .query(ContactsContract.Contacts.CONTENT_URI,  
  121.                             CONTACTS_COLUMN_NAMES, null, null,  
  122.                             ContactsContract.PhoneLookup.DISPLAY_NAME);  
  123.             while (allContacts.moveToNext()) {  
  124.                 // 返回第二列的值 也就是 ContactsContract.PhoneLookup.TIMES_CONTACTED的值  
  125.                 // the zero-based index  
  126.                 String timesContacted = "Times contacted: "  
  127.                         + allContacts.getInt(2);  
  128.   
  129.                 Object[] rowObject = new Object[] {  
  130.                         allContacts.getLong(0), // id  
  131.                         allContacts.getString(1), // name  
  132.                         timesContacted, // description  
  133.                         Uri.parse("content://com.android.contacts/contacts/"  
  134.                                 + allContacts.getLong(0)), // intent uri  
  135.                         cp.getContext().getPackageName(), // package 返回应用程序的包名称  
  136.                         R.drawable.contacts // 返回我们LiveFolder的图标  
  137.                 };  
  138.                 // 给我们的 MatrixCursor 对象mc 添加给定的列值  
  139.                 mc.addRow(rowObject);  
  140.             }  
  141.             // 返回MatrixCursor对象  
  142.             return mc;  
  143.         } finally {  
  144.             // 关闭Cursor对象, 并释放所有资源并使其无效  
  145.             allContacts.close();  
  146.         }  
  147.     }  
  148.   
  149.     // 如果有自定义类型,必须实现此方法 这里我们 用的是 系统定义好的类型  
  150.     @Override  
  151.     public String getType(Uri uri) {  
  152.         // indicates the MIME type for a given URI  
  153.         // targeted for this wrapper provier  
  154.         // This usually looks like  
  155.         // "vnd.android.cursor.dir/vnd.google.note"  
  156.         return ContactsContract.Contacts.CONTENT_TYPE;  
  157.   
  158.     }  
  159.   
  160.     @Override  
  161.     public Uri insert(Uri uri, ContentValues values) {  
  162.         throw new UnsupportedOperationException(  
  163.                 "no insert as this is just a wrapper");  
  164.     }  
  165.   
  166.     @Override  
  167.     public int delete(Uri uri, String selection, String[] selectionArgs) {  
  168.         throw new UnsupportedOperationException(  
  169.                 "no delete as this is just a wrapper");  
  170.     }  
  171.   
  172.     @Override  
  173.     public int update(Uri uri, ContentValues values, String selection,  
  174.             String[] selectionArgs) {  
  175.         throw new UnsupportedOperationException(  
  176.                 "no update as this is just a wrapper");  
  177.     }  
  178.   
  179. }  

先说一下 timesContacted,它是用来记录 我们的联系人呼叫我我们几次 比如你电话存着 女朋友的电话 timesContacted就记录着你女朋友给你打了几个电话,或者说呼叫了你几次,还有就连这个也可以时时更新,所以说还是比较强大的。 

     INTENT 字段实际上是一个字符串,指向 ContentProvider 中该项的URL。在用户单击该项时,Android将使用此URL 来调用VIEW操作。此字符串字段称为 INTENT 字段是因为,在内部,Android会从字符串 URI 派生 INTENT。 

 

 

 

   方法 loadNewData() 从联系人提供程序获取一组联系人并创建 MatrixCursor,MatrixCursor对象包含我们需要的列。这段代码然后告诉 MatrixCursor 向 ContentResolver 注册自身,以便在URI (content://com.android.contacts/contacts/) 所指向的数据以任何形式发生变化时,ContentResolver能够提醒游标也就是我们的Cursor对象

 

MyCursor对象是我们自己定义的一个Cursor对象,这里要理解为什么需要包装游标,需要了解视图如何更新更改的内容。ContentProvider(比如Contacts)通常通过将一个URI 注册为 query方法实现的一部分,告诉游标它需要监视更改。这是通过 cursor.setNotificationUri完成的。游标然后将向 ContentProvider 注册此URI 及它的所有子URI。然后,当在 ContentProvider 上发生插入或删除操作时,插入或删除操作的代码需要发出一个事件,表示特定URI 所标识的行中的数据发生了更改。

    这将出发游标通过 requery进行更新,视图也将相应更新。遗憾的是, MatrixCursor不适用此 requery。SQLiteCursor适用于它,但我们无法在这里使用 SQLiteCursor,因为我们已将这些列映射到了一组新列。

    为了解决这一限制,我们将MatrixCursor包装到一个游标包装器中,并重写 requery 方法以丢弃内部的 MatrixCursor,并使用更新的数据创建一个新游标。更明确的讲,每次数据更改时,我们都希望获得新的 MatrixCursor。但我们仅向 Android活动文件夹框架返回所包装的外部游标。这将告诉活动文件夹框架只有一个游标,但在后台,当数据更改时我们会创建新游标,我们下面来说说这两个类。

 

4. MyCursor.java

 

MyCursor最开始使用一个 MatrixCursor进行初始化。在requery上, MyCursor 将回调提供程序来返回一个 MatrixCursor。然后,新 MatrixCursor 将使用 set 方法替代旧 MatrixCursor。

说明:可以通过重写 MatrixCursor的requery来完成此任务,但该类无法清除数据并重新启动。所以这是一种合理的解决办法。

 

 

 
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.content.ContentProvider;  
  4. import android.database.MatrixCursor;  
  5.   
  6. public class MyCursor extends BetterCursorWrapper {  
  7.   
  8.     private ContentProvider mcp = null;  
  9.   
  10.     public MyCursor(MatrixCursor mc, ContentProvider inCp) {  
  11.         super(mc);  
  12.         mcp = inCp;  
  13.     }  
  14.   
  15.     @Override  
  16.     public boolean requery() {  
  17.         MatrixCursor mc = MyContactsProvider.loadNewData(mcp);  
  18.         this.setInternalCursor(mc);  
  19.         return super.requery();  
  20.     }  
  21.   
  22. }  

5.    BetterCursorWrapper.java

 

BetterCursorWrapper类 非常类似于 Android数据库框架中的 CursorWrapper类。但我们还需要 CursorWrapper 所缺少的另外两项功能。首先,它没有提供 set方法来替换 requery 方法中的内部游标。其次, CursorWrapper 不是CrossProcessCursor。活动文件夹需要 CrossProcessCursor,而不是普通游标,因为活动文件夹会跨进程边界进行工作。
BetterCursorWrapper源代码:

 

 
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.content.ContentResolver;  
  4. import android.database.CharArrayBuffer;  
  5. import android.database.ContentObserver;  
  6. import android.database.CrossProcessCursor;  
  7. import android.database.CursorWindow;  
  8. import android.database.DataSetObserver;  
  9. import android.net.Uri;  
  10. import android.os.Bundle;  
  11.   
  12. public class BetterCursorWrapper implements CrossProcessCursor {  
  13.   
  14.     // Holds the internal cursor to delegate methods to  
  15.     protected CrossProcessCursor internalCursor;  
  16.   
  17.     public CursorWindow getWindow() {  
  18.         return internalCursor.getWindow();  
  19.     }  
  20.   
  21.     public boolean onMove(int oldPosition, int newPosition) {  
  22.         return internalCursor.onMove(oldPosition, newPosition);  
  23.     }  
  24.   
  25.     public int getCount() {  
  26.         return internalCursor.getCount();  
  27.     }  
  28.   
  29.     public int getPosition() {  
  30.         return internalCursor.getPosition();  
  31.     }  
  32.   
  33.     public boolean move(int offset) {  
  34.         return internalCursor.move(offset);  
  35.     }  
  36.   
  37.     public boolean moveToPosition(int position) {  
  38.         return internalCursor.moveToPosition(position);  
  39.     }  
  40.   
  41.     public boolean moveToFirst() {  
  42.         return internalCursor.moveToFirst();  
  43.     }  
  44.   
  45.     public boolean moveToLast() {  
  46.         return internalCursor.moveToLast();  
  47.     }  
  48.   
  49.     public boolean moveToNext() {  
  50.         return internalCursor.moveToNext();  
  51.     }  
  52.   
  53.     public boolean moveToPrevious() {  
  54.         return internalCursor.moveToPrevious();  
  55.     }  
  56.   
  57.     public boolean isFirst() {  
  58.         return internalCursor.isFirst();  
  59.     }  
  60.   
  61.     public boolean isLast() {  
  62.         return internalCursor.isLast();  
  63.     }  
  64.   
  65.     public boolean isBeforeFirst() {  
  66.         return internalCursor.isBeforeFirst();  
  67.     }  
  68.   
  69.     public boolean isAfterLast() {  
  70.         return internalCursor.isAfterLast();  
  71.     }  
  72.   
  73.     public int getColumnIndex(String columnName) {  
  74.         return internalCursor.getColumnIndex(columnName);  
  75.     }  
  76.   
  77.     public int getColumnIndexOrThrow(String columnName)  
  78.             throws IllegalArgumentException {  
  79.         return internalCursor.getColumnIndexOrThrow(columnName);  
  80.     }  
  81.   
  82.     public String getColumnName(int columnIndex) {  
  83.         return internalCursor.getColumnName(columnIndex);  
  84.     }  
  85.   
  86.     public String[] getColumnNames() {  
  87.         return internalCursor.getColumnNames();  
  88.     }  
  89.   
  90.     public int getColumnCount() {  
  91.         return internalCursor.getColumnCount();  
  92.     }  
  93.   
  94.     public byte[] getBlob(int columnIndex) {  
  95.         return internalCursor.getBlob(columnIndex);  
  96.     }  
  97.   
  98.     public String getString(int columnIndex) {  
  99.         return internalCursor.getString(columnIndex);  
  100.     }  
  101.   
  102.     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {  
  103.         internalCursor.copyStringToBuffer(columnIndex, buffer);  
  104.     }  
  105.   
  106.     public short getShort(int columnIndex) {  
  107.         return internalCursor.getShort(columnIndex);  
  108.     }  
  109.   
  110.     public int getInt(int columnIndex) {  
  111.         return internalCursor.getInt(columnIndex);  
  112.     }  
  113.   
  114.     public long getLong(int columnIndex) {  
  115.         return internalCursor.getLong(columnIndex);  
  116.     }  
  117.   
  118.     public float getFloat(int columnIndex) {  
  119.         return internalCursor.getFloat(columnIndex);  
  120.     }  
  121.   
  122.     public double getDouble(int columnIndex) {  
  123.         return internalCursor.getDouble(columnIndex);  
  124.     }  
  125.   
  126.     public boolean isNull(int columnIndex) {  
  127.         return internalCursor.isNull(columnIndex);  
  128.     }  
  129.   
  130.     public void deactivate() {  
  131.         internalCursor.deactivate();  
  132.     }  
  133.   
  134.     public boolean requery() {  
  135.         return internalCursor.requery();  
  136.     }  
  137.   
  138.     public void close() {  
  139.         internalCursor.close();  
  140.     }  
  141.   
  142.     public boolean isClosed() {  
  143.         return internalCursor.isClosed();  
  144.     }  
  145.   
  146.     public void registerContentObserver(ContentObserver observer) {  
  147.         internalCursor.registerContentObserver(observer);  
  148.     }  
  149.   
  150.     public void unregisterContentObserver(ContentObserver observer) {  
  151.         internalCursor.unregisterContentObserver(observer);  
  152.     }  
  153.   
  154.     public void registerDataSetObserver(DataSetObserver observer) {  
  155.         internalCursor.registerDataSetObserver(observer);  
  156.     }  
  157.   
  158.     public void unregisterDataSetObserver(DataSetObserver observer) {  
  159.         internalCursor.unregisterDataSetObserver(observer);  
  160.     }  
  161.   
  162.     public void setNotificationUri(ContentResolver cr, Uri uri) {  
  163.         internalCursor.setNotificationUri(cr, uri);  
  164.     }  
  165.   
  166.     public boolean getWantsAllOnMoveCalls() {  
  167.         return internalCursor.getWantsAllOnMoveCalls();  
  168.     }  
  169.   
  170.     public Bundle getExtras() {  
  171.         return internalCursor.getExtras();  
  172.     }  
  173.   
  174.     public Bundle respond(Bundle extras) {  
  175.         return internalCursor.respond(extras);  
  176.     }  
  177.   
  178.     // Constructor takes a crossprocesscursor as an input  
  179.     public BetterCursorWrapper(CrossProcessCursor inCursor) {  
  180.         this.setInternalCursor(inCursor);  
  181.     }  
  182.   
  183.     // You can reset in one of the derived class's method  
  184.     public void setInternalCursor(CrossProcessCursor inCursor) {  
  185.         internalCursor = inCursor;  
  186.     }  
  187.   
  188.     @Override  
  189.     public void fillWindow(int pos, CursorWindow winow) {  
  190.         internalCursor.fillWindow(pos, winow);  
  191.     }  
  192.   
  193. }  

大家看前几个方法就行了,后边方法都没有用到 实现CrossProcessCursor这个接口就会实现这些方法。大家也可以用 Eclipse 自动生成一下,将光标放在 internalCursor上。用鼠标右键单击并选择 Source---》GenerateDelegate Methods。Eclipse随后将填充该类剩余部分。现在看一下完成此示例需要的一个简单activity. 

 

 


6 .SimpleActivity.java:

SimpleActivity.java 不是活动文件夹必须的类,但在项目中包含它可以为所有项目提供一种通用模式。此外,它支持在通过 Eclipse调试时,部署应用程序并在屏幕上查看它。

 

 

 
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5.   
  6. public class SimpleActivity extends Activity {  
  7.     /** Called when the activity is first created. */  
  8.     @Override  
  9.     public void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.main);  
  12.     }  
  13. }  

XML 布局文件:

 

 

 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <TextView android:layout_width="fill_parent"  
  6.         android:layout_height="wrap_content" android:text="Live Folder Example" />  
  7. </LinearLayout>  

完成这些就可以进行部署条数了.刚打开会打开一个Activity 就是我们上边的那个SimpleActivity 然后我们切换到主页 按照我们 最开始 介绍的步骤就可以建立 活动文件夹了