活動目錄(LiveFolder)是一種小型的應用層插件。它本身展現為桌面出現的圖示,通過點選這些圖示,将出現一個清單框,清單框中将顯示資料資訊。通過活動目錄可以在不打開應用程式的情況下,在桌面就能檢視其中的資料資訊。
在Android的桌面中長按桌面或者選擇菜單,進入增加活動目錄的界面,可以将LiveFolder增加到桌面,LiveFolder的增加界面和運作效果如圖8-4所示。
圖8-4中左圖為增加LiveFolder的界面,清單中的内容由各個應用程式實作的增加LiveFolder的入口決定。LiveFolder點選後不會啟動Activity,而是在出現類似圖8-4中右圖的界面的對話框。這個對話框不是LiveFolder實作者的一部分,而是桌面程式提供的功能。對話框通常包含一個清單,LiveFolder實作者可以實作其中的每個項目顯示的内容,還可以進一步實作每個内容被點選之後,出現的界面。如果僅僅出現活動目錄清單項對話框,實際是LiveFolder實作者并沒有提供運作的界面,而隻是在桌面檢視了其中的内容。
▲圖8-4 活動目錄增加界面和運作效果(左:增加界面;中:Contacts活動目錄;
右:Contacts活動目錄的點選效果)
LiveFolder的程式組成
LiveFolder插件的本質是一個特殊的Activity和一個特殊的ContentProvider。Activity需要支援特殊的Intent動作,負責建立LiveFolder,并通過URI關聯到某個ContentProvider;ContentProvider負責提供LiveFolder中使用的各個項目的内容。
android.provider包的LiveFolders類定義活動目錄的Activity和ContentProvider中的特殊内容。
1.LiveFolder的Activity
在Activity方面,LiveFolders類中的ACTION_CREATE_LIVE_FOLDER動作,實際表示的字元串為“android.intent.action.CREATE_LIVE_FOLDER”。接受這個Intent-filter的Activity,将被桌面程式選擇作為可以建立LiveFolder的程式。
Activity在收到ACTION_CREATE_LIVE_FOLDER動作的Intent啟動後,要通過setResult()調用的方式把活動目錄的内容發回給它的調用者。傳回的Intent的核心内容是需要設定一個Uri,表示活動目錄要查詢的ContentProvider的位址。
LiveFolders類中的另外幾個數值表示建立LiveFolder後傳回的附加參數。
EXTRA_LIVE_FOLDER_NAME:表示所建立的活動目錄的名稱(也就是出現在桌面的标簽),為字元串“android.intent.extra.livefolder.NAME”,類型為String。
EXTRA_LIVE_FOLDER_ICON:表示活動目錄在桌面顯示的圖示,為字元串“android.intent.extra.livefolder.ICON”,類型為Intent.ShortcutIconResource(作為Parcelable傳遞)。
EXTRA_LIVE_FOLDER_DISPLAY_MODE:表示活動目錄的顯示模式,為字元串“android.intent.extra.livefolder.DISPLAY_MODE”,類型為int ,具有兩個數值可以使用:DISPLAY_MODE_GRID(網格)和DISPLAY_MODE_LIST(清單)。
EXTRA_LIVE_INTENT:表示活動目錄中某個項目被點選後,啟動内容的Intent,為字元串“android.intent.extra.livefolder.BASE_INTENT”,類型為Intent。
綜合以上幾個方面,LiveFolders被建立後,傳回的Intent比較特殊,這個Intent實際上用于指向一個内容提供者,其中的Data域就是指向這個内容提供者的URI。它的額外參數定義了展現在桌面上的名稱和圖示,也展現了點選桌面圖示後出現的對話框中的内容。
LiveFolder增加到桌面後的圖示和選擇LiveFolder的圖示可以不同。在習慣上,為了差別桌面的Shotcut,LiveFolder的圖示通常做成類似檔案夾的形式。
2.LiveFolder的ContentProvider
在ContentProvider方面,需要在查詢(query())的時候,支援幾個特殊的域。這些域由LiveFolders類的幾個常量定義,如下所示。
NAME:表示每個項目的名稱,為字元串“name”,類型為String;
DESCRIPTION:表示每個項目的描述,為字元串“description”,類型為String;
INTENT:表示每個項目被選中後啟動的内容,為字元串“intent”,類型為Intent;
ICON_BITMAP:表示每個項目的圖示,為字元串“icon_bitmap”,類型為Bitmap;
ICON_PACKAGE:表示項目圖示對應的應用程式包的名字,為字元串“icon_ package”,類型為String;
ICON_RESOURCE:表示項目圖示對應的資源名稱,為字元串“icon_resource”,類型為Parcelable。
對于LiveFolder的ContentProvider的實作,以上的幾個域隻有NAME必須實作,其他是可選的。
LiveFolders實作了BaseColumns接口,是以其中也含有兩個靜态屬性。
_ID:内容的id,為字元串“_count”,類型為INTEGER;
_COUNT:内容的數目,為字元串“_id”,類型為INTEGER。
實作LiveFolder的ContentProvider也需要支援_ID和_COUNT兩個域。
LiveFolder的實作
本節中的LiveFolder Sample程式實作了一個活動目錄,增加後将在桌面出現一個圖示。點選這個活動目錄在桌面的圖示,将在LiveFolder的清單框中顯示一些内容。LiveFolder Sample的執行效果如圖8-5所示。
圖8-5中右圖的清單項對話框共有8個項目,進一步點選每一個項目,還将出現浏覽器顯示空(blank)的網頁。
LiveFolder Sample實作的AndroidMenifest.xml中定義的一個用于建立LiveFolder 的Activity和一個顯示内容的ContentProvider,如下所示:
<activity android:name="LiveFolderSample"
android:icon="@drawable/app_icon" android:label="LiveFolder Sample">
<intent-filter>
<action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<provider android:name="LiveFolderSampleProvider"
android:authorities="livefoldersample"/>
▲圖8-5 LiveFolder Sample(左:增加界面;中:LiveFolder的桌面圖示;右:啟動對話框)
這裡聲明的Activity支援“android.intent.action.CREATE_LIVE_FOLDER”動作,表示可以用它來建立活動目錄,也就是可能在活動目錄的增加清單中出現它這個項目。
public class LiveFolderSample extends Activity {
private static final String URI = // ContentProvider的URI
"content://" + "livefoldersample" + "/live_folders/virtual";
private static final Uri CONTENT_URI = Uri.parse(URI);
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent(); // 獲得其中的Intent
final String action = intent.getAction();
if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
final Intent liveFolderIntent = new Intent(); // 傳回結果中的Intent
final Intent urlIntent =
new Intent(Intent.ACTION_VIEW,Uri.parse("about://blank"));
returnIntent.setData(CONTENT_URI); // Intent中的URI
returnIntent.putExtra( // LiveFolder對話框的名稱
LiveFolders.EXTRA_LIVE_FOLDER_NAME,"LiveFolderSample");
returnIntent.putExtra( // LiveFolder的圖示
LiveFolders.EXTRA_LIVE_FOLDER_ICON,Intent.ShortcutIconResource.
fromContext(this,R.drawable.app_icon));
returnIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
LiveFolders.DISPLAY_MODE_LIST);
returnIntent.putExtra( // LiveFolder中的每個内容Intent
LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT,urlIntent);
setResult(RESULT_OK, returnIntent); // 設定傳回結果
} else { setResult(RESULT_CANCELED); }
finish();
}
}
在建立LiveFolder的過程中,涉及兩個Intent。returnIntent是Activity傳回的效果,在其中通過額外參數指定圖示和活動目錄的名稱,其中主要的内容是指向ContentProvider的URI,并定義了其中的圖示和名稱。
傳回内容returnIntent的一個特殊的域為urlIntent,也是一個Intent,它表示每一個項目被點選之後啟動Activity的Intent。在這裡将它定義為Intent.ACTION_VIEW 動作和以“about://blank”表示的Intent。當點選LiveFolder中的每一個項目的時候,将調用相應的程式(實際上是浏覽器),對應的URI為“about://blank”再附加上每個内容的id。
這裡的ContentProvider的實作内容如下所示:
public class LiveFolderSampleProvider extends ContentProvider {
private static final int VIRTUAL = 1; // 各個項目的id
private static final int VIRTUAL_ID = 2;
private static final int LIVE_FOLDER_SAMPLE = 3;
public static final String AUTHORITY = "livefoldersample"; // URI
private static final UriMatcher sUriMatcher;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 建立比對器
sUriMatcher.addURI(AUTHORITY, "virtual/", VIRTUAL);
sUriMatcher.addURI(AUTHORITY, "virtual/#", VIRTUAL_ID);
sUriMatcher.addURI(AUTHORITY, "live_folders/virtual", LIVE_FOLDER_SAMPLE);
// ...... 省略部分内容:query()方法的實作
@Override public String getType(Uri uri) { // 擷取類型的實作
switch (sUriMatcher.match(uri)) {
case VIRTUAL:
case VIRTUAL_ID:
return "";
case LIVE_FOLDER_SAMPLE:
return "";
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
@Override public boolean onCreate() { return true; }
@Override public Uri insert(Uri uri, ContentValues initialValues) {
return null; // LiveFolder不要求實作insert()
@Override public int delete(Uri uri, String where, String[] whereArgs) {
return 0; // LiveFolder不要求實作delete()
@Override public int update(Uri uri, ContentValues values,
String where, String[] whereClause) {
return 0; // LiveFolder不要求實作update()
對于為LiveFolder使用的ContentProvider,需要實作getType()方法,而其他方法不是必需的,如果要實作,可以在其他的地方對ContentProvider進行操作。
query()方法的實作是主要的内容,如下所示:
@Override public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs,String sortOrder) {
switch (sUriMatcher.match(uri)) { // 查詢操作的比對
case VIRTUAL: // 不傳回實際内容
return null;
case LIVE_FOLDER_SAMPLE:
return getLivefolder(); // 調用傳回内容
private Cursor getLivefolder() { // 傳回具體的内容
int i = 0;
String[] columnNames = {LiveFolders._ID,LiveFolders.NAME}; // 2個必要的列
String[] temp = {"",""};
MatrixCursor c = new MatrixCursor(columnNames);
for(i = 0 ;i < 8;i++){ // 循環傳回8個項目
temp[0] = String.valueOf(i); // _ID的内容
temp[1] = LiveFolders.NAME + " = " + String.valueOf(i); // NAME的内容
c.addRow(temp);
return c;
在查詢傳回的時候,實際上隻有一個項有效,聯系ContentProvider和LiveFolder建立者的是名稱為“content://livefoldersample/live_folders/virtual”的URI。
查詢傳回具有兩列的内容,其中第一列為_ID,第二列為NAME。前者表示每列的id,這是必須具有的,後者也就是反映在LiveFolder對話框中的每個項目顯示的内容。
由于在這裡沒有為每個項目設定Intent域(LiveFolders.INTENT),是以每個項目在被選擇之後将根據LiveFolder的建立者中設定的Intent附加上每個項目的id,作為啟動的内容。例如,點選第2個項目将打開名稱為“about://blank/1”的位址的空網頁。
本文轉自 wws5201985 51CTO部落格,原文連結:http://blog.51cto.com/wws5201985/796642,如需轉載請自行聯系原作者