Android Launcher开发之LiveFolder(实时文件夹) 完全解析(2)

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

package xiaohang.zhimeng;      import Android.app.Activity;   import android.content.Intent;   import android.net.Uri;   import android.os.Bundle;   import android.provider.LiveFolders;      public class AllContactsLiveFolderCreatorActivity extends Activity {          @Override       protected void onCreate(Bundle savedInstanceState) {           super.onCreate(savedInstanceState);              final Intent intent = getIntent();           final String action = intent.getAction();           System.out.println("action is " + action);           if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {               // 设置本Activity返回的结果                setResult(                       RESULT_OK,                       createLiveFolder(MyContactsProvider.CONTACTS_URI,                               "Contacts LF", R.drawable.contacts));           } else {               setResult(RESULT_CANCELED);           }           finish();       }          private Intent createLiveFolder(Uri uri, String name, int icon) {           final Intent intent = new Intent();           intent.setData(uri);           // 设置LiveFolder 的Name(这个名字是显示在手机的主页上的)            intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);           // 设置LiveFolder 的图标            intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,                   Intent.ShortcutIconResource.fromContext(this, icon));           // 指定LiveFolder 显示的模式 这里用List以列表的形式显示            intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,                   LiveFolders.DISPLAY_MODE_LIST);           return intent;       }   }  

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

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

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

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

package xiaohang.zhimeng;      import android.content.ContentProvider;   import android.content.ContentValues;   import android.content.UriMatcher;   import android.database.Cursor;   import android.database.MatrixCursor;   import android.net.Uri;   import android.provider.BaseColumns;   import android.provider.ContactsContract;   import android.provider.LiveFolders;   import android.util.Log;      public class MyContactsProvider extends ContentProvider {          public static final String AUTHORITY = "com.ai.livefolders.contacts";          // Uri that goes as input to the live-folder creation        public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITY               + "/contacts");          // To distinguish this URI        private static final int TYPE_MY_URI = 0;       private static final UriMatcher URI_MATCHER;       static {           URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);           URI_MATCHER.addURI(AUTHORITY, "contacts", TYPE_MY_URI);       }          @Override       public boolean onCreate() {           return true;       }          @Override       public int bulkInsert(Uri uri, ContentValues[] values) {           return 0;       }          // Set of columns needed by a live folder        // This is the live-folder contract        private static final String[] CURSOR_COLUMNS = new String[] {               BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION,               LiveFolders.INTENT, LiveFolders.ICON_PACKAGE,               LiveFolders.ICON_RESOURCE };          // In case there are no rows        // use this stand-in as an error message        // Notice it has the same set of columns of a live folder        private static final String[] CURSOR_ERROR_COLUMNS = new String[] {               BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION };          // The error message row        private static final Object[] ERROR_MESSAGE_ROW = new Object[] { -1// id                "No contacts found"// name                "Check your contacts database" // description        };          // The error cursor to use        private static MatrixCursor sErrorCursor = new MatrixCursor(               CURSOR_ERROR_COLUMNS);       static {           // 为 CURSOR_ERROR_COLUMNS 添加给定的列值            sErrorCursor.addRow(ERROR_MESSAGE_ROW);       }          // Columns to be retrieved from the contacts database        private static final String[] CONTACTS_COLUMN_NAMES = new String[] {               ContactsContract.PhoneLookup._ID,               ContactsContract.PhoneLookup.DISPLAY_NAME,               ContactsContract.PhoneLookup.TIMES_CONTACTED,               ContactsContract.PhoneLookup.STARRED,               ContactsContract.PhoneLookup.PHOTO_ID };          @Override       public Cursor query(Uri uri, String[] projection, String selection,               String[] selectionArgs, String sortOrder) {           // Figure out the uri and return error if not matching            int type = URI_MATCHER.match(uri);           if (type == UriMatcher.NO_MATCH) {               // 如果URI 匹配出错则返回错误信息                return sErrorCursor;           }              Log.i("ss""query called");              try {               // 调用 loadNewData方法进行查询 返回 匹配好的MatrixCursor对象                MatrixCursor mc = loadNewData(this);               // setNotificationUri方法用来指定一个Uri以观察它的变化                // 参数一:需要一个ContentResolver对象,从上下文对象获得                // 参数二:要监视的URI                mc.setNotificationUri(getContext().getContentResolver(),                       Uri.parse("content://com.android.contacts/contacts/"));               MyCursor wmc = new MyCursor(mc, this);               return wmc;           } catch (Exception e) {               System.out.println("Print yi chang ");               // 返回我们的错误对象                return sErrorCursor;           }          }          public static MatrixCursor loadNewData(ContentProvider cp) {           //            MatrixCursor mc = new MatrixCursor(CURSOR_COLUMNS);           Cursor allContacts = null;           try {               // 说一下query方法的参数                /*               * 参数一:要查询的URI 我们查询的完整URI 为"content://com.android.contacts/contacts"               * 也就是所有的联系人参数二:都要查询那些列 上边我们已经定义好参数三:本质上就是一个WHERE子句,它以SQL               * WHERE子句(不包含WHERE本身) 的格式声明要返回的行 传递null将返回给定URI 的所有行               * 参数四:用来替换where子句中的?号参数五:指定排序的方式               */               allContacts = cp                       .getContext()                       .getContentResolver()                       .query(ContactsContract.Contacts.CONTENT_URI,                               CONTACTS_COLUMN_NAMES, nullnull,                               ContactsContract.PhoneLookup.DISPLAY_NAME);               while (allContacts.moveToNext()) {                   // 返回第二列的值 也就是 ContactsContract.PhoneLookup.TIMES_CONTACTED的值                    // the zero-based index                    String timesContacted = "Times contacted: "                           + allContacts.getInt(2);                      Object[] rowObject = new Object[] {                           allContacts.getLong(0), // id                            allContacts.getString(1), // name                            timesContacted, // description                            Uri.parse("content://com.android.contacts/contacts/"                                   + allContacts.getLong(0)), // intent uri                            cp.getContext().getPackageName(), // package 返回应用程序的包名称                            R.drawable.contacts // 返回我们LiveFolder的图标                    };                   // 给我们的 MatrixCursor 对象mc 添加给定的列值                    mc.addRow(rowObject);               }               // 返回MatrixCursor对象                return mc;           } finally {               // 关闭Cursor对象, 并释放所有资源并使其无效                allContacts.close();           }       }          // 如果有自定义类型,必须实现此方法 这里我们 用的是 系统定义好的类型        @Override       public String getType(Uri uri) {           // indicates the MIME type for a given URI            // targeted for this wrapper provier            // This usually looks like            // "vnd.android.cursor.dir/vnd.google.note"            return ContactsContract.Contacts.CONTENT_TYPE;          }          @Override       public Uri insert(Uri uri, ContentValues values) {           throw new UnsupportedOperationException(                   "no insert as this is just a wrapper");       }          @Override       public int delete(Uri uri, String selection, String[] selectionArgs) {           throw new UnsupportedOperationException(                   "no delete as this is just a wrapper");       }          @Override       public int update(Uri uri, ContentValues values, String selection,               String[] selectionArgs) {           throw new UnsupportedOperationException(                   "no update as this is just a wrapper");       }      }  

先说一下 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活动文件夹框架返回所包装的外部游标。这将告诉活动文件夹框架只有一个游标,但在后台,当数据更改时我们会创建新游标,我们下面来说说这两个类。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/f8645387b9acdb3b29783bed343d30da.html