Pro Android學習筆記(三三):Menu(4):Alternative菜單

來源:互聯網
上載者:User

標籤:

什麼是Alternative menu(替代菜單)

舉個例子,Activity顯示一個文字檔。如果使用者想對文字檔進行編輯,Activity不提供編輯能力,但可由其他activity或者其他應用提供。我們將相關資訊儲存在一個intent中,例如該文本的Uri。這個intent可以匹配系統的多個應用,替代菜單將這些應用一一列出,功能表項目的title就是該可被調用的activity的名字,表徵圖也為該可被調用的activity的圖表。

小例子說明

我們通過一個小例子進行學習,簡單地開啟一個URL:wei://flowingflying/helloworld。在之前Intent的學習中,我們通過schema的配置,匹配該URL,也就是我們已經有其他應用的Activity(Intent Basic Test)可以開啟該URL。我們同時在App中新增一個activity也能開啟該URL。這樣,將在alternative菜單中加入兩個功能表項目,點擊它們,將開啟相應的activity,並通過intent傳遞相關的資料資訊。

新增的acitivity名字為Invoke Action(好像應該是invoked才對,不好意思)。在AndroidManifest.xml中加入intent-fliter的描述即可,具體見:Pro Android學習筆記(十一):瞭解Intent(中) 。

<activity android:name=".InvokeAction" android:label="@string/invokeAction" android:icon="@drawable/leaf" >
    <intent-filter > 
        <action android:name="android.intent.action.VIEW" /> 
        <data android:scheme="wei" /> 
        <category android:name="android.intent.category.DEFAULT" /> 
        <category android:name="android.intent.category.ALTERNATIVE" /><!-- 將在最後討論 -->
    </intent-filter> 
</activity> 

Alternative menu代碼

我們看看如何將替代菜單加入到OptionMenu中。Alternative menu還可以載入subMenu,Context Menu中。

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // 對比:加入一個普通功能表項目  
    menu.add("普通功能表項目");  

    //【步驟1】設定intent,本例簡單實用一個已知的Uri。
    Intent menuIntent = new Intent(null,Uri.parse("wei://flowingflying/helloWorld")); 

    //【步驟2】加入Alternative菜單。在之前的Item ID類別中已經講過,Android對ID進行了劃分,有alternative的ID範圍。
    int menuGroup = Menu.CATEGORY_ALTERNATIVE; 
    int startingItemId = Menu.CATEGORY_ALTERNATIVE
    int orderId = Menu.CATEGORY_ALTERNATIVE;  
    menu.addIntentOptions(  //返回增加的功能表項目數目,本例為2
            menuGroup,  /* int groupId */ 
            startingItemId,  /* int itemId:由於自動跳轉到,此參數可以設定為Menu.NONE。 */
            orderId,   /*int order*/ 
            this.getComponentName(), /* ComponentName caller:當前的activity名字,這是android系統處理alternatice menu是調用的queryIntentActivityOptions()函數所需要的參數。getComponentName()返回package名字和class名字,系統以此獲知源activity是誰。 */
            null,  /* Intent[] specifics:匹配可能有多個intent,此用於過濾,但具體用途不詳 */
            menuIntent,  /* Intent intent:關鍵的intent */
            0,  /* flages:關於items如何加入。0表示 no flag*/
            null);  /* MenuItem[] outSpecificItems ,與specifice相關*/

    return super.onCreateOptionsMenu(menu); 

關於Category和規範代碼寫法

我們注意到,在被喚起的actvity中有下面的描述:

[html] view plaincopy 
  1. <category android:name="android.intent.category.ALTERNATIVE" />  

在實驗中,發現此項可有可無,並不真正影響結果。而在reference中卻明確表示要為CATEGORY_ALTERNATIVE或者CATEGORY_SELECTED_ALTERNATIVE。為何?

我們以Alternative menu的方式調用其他activity,正規的做法是,被喚起的activity應允許被alternative菜單喚起。因此被喚起的activity在intent-fliter中需給出類別。同時alternative菜單的intent也應當標明自己類型。因此規範的代碼是:

Intent menuIntent = new Intent(null,this.getIntent().getData()); 
menuIntent.addCategory(Intent.CATEGORY_ALTERNATIVE); 

在小例子中,由於其他應用的Activity(Intent Basic Test)在Manifest XML中並沒有給出相應的類別,不被匹配。運行結果

關於flags

menu.addIntentOptions()的倒數第二個參數是flags,表示功能表項目添加的方式。0,即預設,表示如果groupId相同,則替代菜單將取代原有的功能表項目設定。如果我們想保留原有的同一Group的功能表項目,可以將flags設定為Menu.FLAG_APPEND_TO_GROUP。注意,如果groupId為Menu.NONE是不進行替換的,這個表示不設定GroupId,並非GroupId為0。

多個匹配的itemId等參數

讓我們看看系統是如何?Alternative菜單的。從reference中看到,Menu是一個interface,具體是通過MenuBuilder實現(原始碼見android-17(version)/com/android/internal/view/menu/MenuBuilder.java。相關代碼如下:

public int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller,
        Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
    PackageManager pm = mContext.getPackageManager(); 
    final List<ResolveInfo> lri =  //查詢匹配的Activity資訊 
            pm.queryIntentActivityOptions(caller, specifics, intent, 0); 
    final int N = lri != null ? lri.size() : 0;
    //下面說明如果flag表示FLAG_APPEND_TO_GROUP,會刪除整個group,取而代之
    if ((flags & FLAG_APPEND_TO_GROUP) == 0) { 
        removeGroup(group); 
    } 

    for (int i=0; i<N; i++) { 
        final ResolveInfo ri = lri.get(i); 
        Intent rintent = new Intent( 
            ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]); 
        rintent.setComponent(new ComponentName( 
                ri.activityInfo.applicationInfo.packageName, 
                ri.activityInfo.name)); 
        final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm))
                .setIcon(ri.loadIcon(pm)) 
                .setIntent(rintent);
 
        if (outSpecificItems != null && ri.specificIndex >= 0) {
            outSpecificItems[ri.specificIndex] = item; 
        } 
    } 

    return N; 

從原始碼,可能看出如果有多個匹配,這些功能表項目具有相同的group,相同的id,和相同categoryOrder。雖然我們在小例子中使用了startingItemId,但是實際上itemId是相同的。在小例子中,我們增加了public boolean onOptionsItemSelected(MenuItem item),並在裡面檢查item的參數值,證實確實相同。

這段代碼還說明了功能表項目的名字和圖片為何,以及為何能喚起Activity。採用了setIntent(),是在Pro Android學習筆記(三十):Menu(1):瞭解Menu學習過的的一種觸發機制。

本博文涉及的例子代碼,可以在Pro Android學習:Menu中下載。

Pro Android學習筆記(三三):Menu(4):Alternative菜單

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.