Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 7.1初體驗之應用快捷鍵

Android 7.1初體驗之應用快捷鍵

編輯:關於Android編程

3DTouch技術用於IOS系統以後,受到了果粉的一致推捧。Android用戶的福音來了,App Shortcuts完美的展現了3DTouch,個人感覺比3DTouch更為強大,其不僅僅有3DTouch的效果,同時能為該快捷鍵設置桌面圖標。

這裡寫圖片描述

介紹

使用新的快捷鍵功能將用戶從啟動器直接帶到應用程序中的關鍵操作。用戶只需長按應用程序的啟動器圖標即可顯示應用程序的快捷鍵,然後點按快捷鍵即可跳轉到相關操作,比如建發送新短信,播放視頻,繼續游戲等操作。

Google官方提供了兩種添加快捷鍵的鍵,一種是添加到APK中的資源文件來清單創建應用程序的快捷鍵(即為清單鍵),另外一種是運行時動態添加。對於常用的操作,官方推薦的是使用清單鍵添加,動態鍵顯得更加的靈活,可以根據用戶的喜好來設置,顯得更為人性化。

每個應用程序並不能無限的設定快捷鍵,現官方規定每個應用程序最多設置5個快捷鍵。

清單創建

清單快捷鍵是應用程序內部的通用連接,其有效性與應用程序的版本相關聯。若版本發生的變更,原清單快捷鍵也相應的失效。

這裡寫圖片描述

下面我們來看看如何創建快捷鍵:

1.設定當前應用程序的入口

這地方不用說,都知道為了設置程序的入口,luncher這個activity通過獲取應用程序信息來加載應用程序,顯示給用戶,其中就是通過一個應用程序中的AndroidManifest.xml中的聲明來識別的。
Android.intent.action.MAIN 與 android.intent.category.LAUNCHER 決定應用程序在luncher中的顯示鍵,其中,android.intent.action.MAIN決定應用程序最先啟動的Activity,而android.intent.category.LAUNCHER決定應用程序是否顯示在程序列表裡。

2.添加,引用定義應用程序快捷鍵的資源文件


    
        
            

            
        

        
    


在主入口Activity中,添加上,是為了指定應用程序可以引用定義應用程序快捷鍵的資源文件。其實際意義應該是將主入口的Activity引用變為資源文件中定義的Activity.

快捷鍵打開應用程序時,展現的Activity中引用,打開應用程序時指定跳轉的Activity.


    
        
            

            
        

        
    

    
    

    ***


3.在res/xml目錄下創建shortcuts.xml資源文件。該資源文件指定了,此快鍵鍵相對應的操作,以及快捷鍵相關的UI。



    
        
        
    

    ***


相關API:

android:shortcutId=”a”:設定快捷的ID android:enabled=”true”: 設定該快捷鍵是否可用 android:icon=”@mipmap/ic_1”:快捷鍵的Logo android:shortcutShortLabel=”XX”:快捷鍵的短標簽 android:shortcutLongLabel=”XX”:快捷鍵的長標簽 android:shortcutDisabledMessage=”XX”:當android:enabled設置為false時,此屬性用於顯示自定義禁用消息。 intent:用戶選擇快捷鍵時啟動應用程序的意圖,其中android:action是必須的設置的。 categories:指定快捷鍵類別,當前API支持定義SHORTCUT類別。

注:

之前有提到,應用快捷鍵和應用程序的版本相關聯。如果在後續版本中,使用清單鍵修改了應用快捷鍵,但是版本號沒有修改的話,其快捷鍵並未做改變,除非在修改快捷鍵的同時修改應用程序的版本號。 在application中,通常將打開主入口Activity,而現在打開時資源文件中設定的Activity,暫時設定為ActiviyB.實際上壓在棧底的就是ActiviyB,而不是主Activity,因為此時主Activity並沒有打開。在實際操作時,在回到ActiviyB時,按返回鍵關閉了APP,也有了合理的解釋。 根據API定義,當android:enabled設置為false時,android:shortcutDisabledMessage用來顯示自定義禁用消息。親測的是,我設定了5個快鍵鍵a、b、c、d,並將c,d,e中android:enabled設置為false,實際顯示的只有a、b兩個快鍵鍵,並沒有顯示c、d等快鍵鍵的自定義禁用信息,很難理解是不是,看看以後API更新是否解決此問題吧。 之前有說過一個APP最多設定5個快捷鍵,當我清單設定a、b、c、d、e等五個快捷鍵時,實際顯示的快捷只有a、b、c、d等4個,e並沒有顯示。既然一個APP最多設定5個快捷鍵,可以理解為APP默認的圖標應該為一個快捷鍵,實際上後續添加的快捷鍵應該是4個。 如果長按應用快捷鍵並拖動到桌面的空白處,可以自動生成一個相應的APP的桌面快捷鍵。 親測了快捷鍵的標簽顯示,所謂的長標簽是動態設置快捷鍵時的標簽顯示,而短標簽為清單設置快捷鍵時的標簽顯示。

動態創建

動態創建快捷鍵是在程序運行時,在與上下文相關聯的情況下,創建程序的快捷鍵。

這裡寫圖片描述

ShortcutManager API允許的動態快捷鍵操作如下:

發布:調用setDynamicShortcuts(List)重新定義動態快捷鍵的整個列表,或使用addDynamicShortcuts(List)來擴充現有的動態快捷鍵列表, 更新:調用updateShZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcnRjdXRzo6hMaXN0o6m4/NDCtq/MrL/svd28/MHQse0gyb6z/aO6yrnTw3JlbW92ZUR5bmFtaWNTaG9ydGN1dHOjqExpc3Sjqcm+s/3Su9fptq/MrL/svd28/KOsu/LKudPDcmVtb3ZlQWxsRHluYW1pY1Nob3J0Y3V0c6Ooo6nJvrP9y/nT0LavzKy/7L3dvPyhoyA8L2NvZGU+PC9jb2RlPjwvY29kZT4NCjxoMiBpZD0="相關api">相關API

ShortcutManager

此類用於管理快捷鍵列表。

addDynamicShortcuts(List):擴充現有的動態快捷鍵列表 setDynamicShortcuts(List):重新定義動態快捷鍵的整個列表 updateShortcuts(List):更新動態快捷鍵列表 removeAllDynamicShortcuts():移除所有的快捷鍵列表

removeDynamicShortcuts(List):移除動態設置的快捷鍵列表

disableShortcuts(List):不顯示快捷列表

disableShortcuts(List, CharSequence):禁用部分快捷鍵,並顯示自定義的禁用信息

enableShortcuts(List):如果快捷鍵被禁用,則顯示快捷鍵

getDynamicShortcuts():獲取所有動態設置的快捷鍵,返回值為List

getManifestShortcuts():獲取所有清單設置的快捷鍵,返回值為List getPinnedShortcuts():返回來應用程序的所有固定的快捷方式,並不是動態或者清單設置的快捷方式 getMaxShortcutCountPerActivity():返回每個啟動器圖標一次可以擁有的動態和快捷鍵的最大數量。

ShortcutInfo.Builder

此類用於創建快件鍵。

ShortcutInfo.Builder(context, id):Builder的構造方法,參數分別為上下文、快捷鍵Id setActivity(ComponentName):設置快捷鍵的目標包和目標Activity setCategories(Set):設置快捷鍵的類別 setDisabledMessage(CharSequence):設置快捷鍵被禁用的顯示信息 setExtras(PersistableBundle):打開應用程序時的設置 setIcon(Icon):設置快捷鍵Logo setIntent(Intent):設置快捷鍵意圖 setIntents(Intent[] intents):設置快捷鍵意圖 setShortLabel(CharSequence):快捷鍵的短標簽 setLongLabel(CharSequence):快捷鍵的長標簽 setRank(int):非負值,用於快捷鍵顯示位置排序

ShortcutInfo

此類實例由ShortcutInfo.Builder創建,本身的構造方法並未對外公布,其重要用來查看快捷鍵的相關設置。

ComponentName getActivity():獲取快捷鍵的目標包和目標Activity Set getCategories():獲取快捷鍵的相關類別 CharSequence getDisabledMessage():獲取快捷鍵,被禁用時自定義顯示的信息 CharSequence getShortLabel():獲取快捷鍵短標簽 CharSequence getLongLabel():獲取快捷鍵長標簽 PersistableBundle getExtras():獲取打開應用程序時的設置 String getId():獲取快捷鍵的Id Intent getIntent():獲取快捷鍵的意圖 Intent[] getIntents():獲取快捷鍵的意圖 long getLastChangedTimestamp():獲取快捷鍵最後更改的時間 String getPackage():獲取快捷鍵打開的應用程序的包名 boolean isDeclaredInManifest():快捷鍵是否為清單設置 boolean isDynamic():快捷鍵是否為動態設置 boolean isEnabled():快捷鍵是否可用 boolean isPinned():是否固定了快捷鍵 boolean isImmutable():快捷鍵是否可以修改,若不可以修改,不能使用ShortcutManager相關API修改

使用實例

發布快捷鍵

ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

ShortcutInfo shortcutA = new ShortcutInfo.Builder(this, "id1")
        .setShortLabel("打開ActivityA")
        .setLongLabel("打開ActivityA_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
        .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityA"))
        .build();

ShortcutInfo shortcutB = new ShortcutInfo.Builder(this, "id2")
        .setShortLabel("打開ActivityB")
        .setLongLabel("打開ActivityB_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_2))
        .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityB"))
        .build();
// 若不設置包名和打開Activity的路徑,此時快捷鍵將不知道具體打開哪個一個Activity,也就意味著該快捷鍵設置無效
ShortcutInfo shortcutC = new ShortcutInfo.Builder(this, "id3")
        .setShortLabel("未定義Activity")
        .setLongLabel("未定義Activity_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
        .setIntent(new Intent(Intent.ACTION_VIEW))
        .build();

shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutA, shortcutB, shortcutC));

更新快捷鍵

ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

ShortcutInfo shortcutC = new ShortcutInfo.Builder(this, "id1")
        .setShortLabel("打開ActivityC")
        .setLongLabel("打開ActivityC_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
        .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityC"))
        .build();

ShortcutInfo shortcutD = new ShortcutInfo.Builder(this, "id2")
        .setShortLabel("打開ActivityD")
        .setLongLabel("打開ActivityD_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_2))
        .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityD"))
        .build();

ShortcutInfo shortcutE = new ShortcutInfo.Builder(this, "id3")
        .setShortLabel("打開ActivityE")
        .setLongLabel("打開ActivityE_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
        .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityE"))
        .build();

shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutC, shortcutD, shortcutE));

刪除快捷鍵

ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

shortcutManager.removeDynamicShortcuts(Arrays.asList("id3"));

注:在使用動態創建快捷鍵時,必須在Intent中調用setClassName(package, activity)方法或者在ShortcutInfo.Builder中調用setActivity(ComponentName),指定快捷鍵的的指定包和Activity,否則會出現不知道往哪裡跳轉,而做無效操作。

快捷鍵的Intent

使用快捷鍵打開應用時,為了快速快速打開應用程序並跳轉到應用的某一個功能界面。假如應用程序已經打開,是將棧中的Activity清空還是保留原來棧並打開新的功能界面?下面從動態設置和清單設置兩個方向分別來看。

清單設置

這裡寫圖片描述
從上面看到,進入APP後,進入MainActivity,通過按鈕B打開ActivityB,然後再打開ActivityE,最後通過Home鍵進入桌面。此時應程序的棧中應該有3個Activity,分別是MainActivity、ActivityB和ActivityE,並且ActivityE處於棧頂。長按APP的桌名圖標,通過快捷方式打開應用程序進入ActivityA界面。當我們按返回鍵時,居然直接返回到了桌面,而不是之前棧頂的ActivityE。這是啥情況,百思不得其解。

官方文檔這麼說的,清單方式設置的快捷鍵的Intent不能自定義Intent的Flag,其默認的Flag是FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK。 這意味著,當應用程序已經運行時,當啟動清單快捷方式時,所有現有活動都將被銷毀,然後重新創建一個新的Activity棧。這也能夠清楚的解釋剛才碰到的問題了。面對這樣的問題,官方推薦使用一個中間Activity啟動,或者onCreate(Bundle)中啟動另外一個不可見的活動,然後調用finish()。對於第一個啟動的Activity,通過AndroidManifest.xml文件中包含一個android:taskAffinity =“”的屬性設置其屬於的Activity,並且清單快捷方式中的intent應該指向這個第一個活動。即使MainActivity也是處於此棧中,由於Flag(FLAG_ACTIVITY_CLEAR_TASK)原來所有的活動Activity必然被清空。

當然,在某一個可以聲明多個Intent,並且最後一個Intent為快鍵鍵跳轉的目標Intent。此時,可以將多個Activity壓入棧中,這些Activity都是新建的,故而此棧中的Activity並不一定與原棧中活動的Activity一致。

從上述,可以清楚的看出,清單設置的快捷鍵在打開應用程序時,若應用程序在運行,不管是創建新棧還是通過android:taskAffinity =“”指定了棧,必須首先清空原Activity棧中的所有活動。此種效果是不是實際設計想要的,就需要深思了。

動態設置

這裡寫圖片描述

現動態設置了快捷方式按鈕,操作流程和清單方式一樣,通過快捷鍵啟動用用程序並跳轉到ActivityA,當按返回鍵時,其並沒有返回至桌面,而是返回了ActivityE,意味著在應用程序打開時,若沒有對快捷鍵的目標Activity的棧有特別指定的話,新打開的Activity會在原棧中堆棧。親測如果使用快捷鍵打開B的話,因為對ActivityB的啟動模式為默認的話,會新建一個ActivityB,同時保留原棧中活動的ActivityB。好像這就是我們想要的效果。

讓人郁悶的是,官方並不這麼認為,有這麼一段描述

 otherwise, if the application is already running, the application is simply brought to the foreground, and the target activity may not appear.

這也就意味著,如果應用程序在運行,可能會出現潛在異常,即為只是應用程序回到前台,但並不會跳轉到目標活動。另外,官方對推薦對於目標的Intent設置Flag屬性FLAG_ACTIVITY_CLEAR_TASK,以便於清空原棧中所有的活動Activity。當然如果啟動時,想添加多個目標Activity,可以使用setIntents(Intent [])方法代替setIntent(Intent)與TaskStackBuilder,但是實際效果與清單方式創建快捷鍵基本一致。個人也實際情況測試了,在目標Intent中並不設置flag屬性為FLAG_ACTIVITY_CLEAR_TASK,也沒有出現官方所說的潛在bug。是不是SDK並未完善,google為了效果,現在Android 7.1中推出,值得商榷。

禁用快捷鍵

之前有提到,快捷鍵固定到設備上以後,其與應用程序的版本相關聯,故而會出現快捷鍵會過期或者指向不存在的操作。ShortcutManager作為快捷鍵的管理類,可以動態的通過調用disableShortcuts(List)來禁用不希望用戶選擇的動態快捷方式,這會刪除指定的動態快捷方式,並禁用這些動態快捷方式的任何固定副本。當然,也可以選擇調用 disableShortcuts(List,CharSequence)方法來指定快捷鍵被禁用時所提示的消息。

注:如果更新應用程序時移除部分應用程式的清單快速鍵,系統會自動停用這些捷徑。

快捷鍵顯示順序

當應用程序桌面圖標顯示與其相關聯的快捷鍵時,快捷鍵應按以下順序顯示:優先顯示清單快捷鍵(若isDeclaredInManifest()為true),再顯示動態快捷鍵(若isDynamic()為true)。
在每個類別的快捷方式(清單和動態)中,按照根據getRank()增加排序的順序對快捷方式進行排序。

快捷鍵的屬性值rank是一個非負數,其決定了快捷鍵的顯示順序,如果想更改快捷鍵的顯示順序可以使用updateShortcuts(List)更新快捷的屬性值,或者使用addDynamicShortcuts(List)和setDynamicShortcuts(List)。

清單快捷鍵

在shortcuts.xml定義了兩個快捷鍵,id一次分別為a和b。


    
        
        
    

    
        
        
    


這裡寫圖片描述

從效果的圖中可以,可以看出,清單快捷鍵顯示的順序與其聲明順序是一致的.通過ShortcutManager中的getManifestShortcuts()獲取所有清單設置的快捷鍵,並查看其ranks屬性。從下述代碼中,可以清晰的看出來,其根據默認順序自動增長的。

ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
List shortcutInfoList = shortcutManager.getManifestShortcuts();
for (ShortcutInfo info: shortcutInfoList) {
    Log.i("123", "id:" + info.getId()+ " | ranks:" + info.getRank());
}

//Log
id: a | ranks:0 
id: b | ranks:1 

動態創建

未設置rank

ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

ShortcutInfo shortcutA = new ShortcutInfo.Builder(this, "id1")
        .setShortLabel("打開ActivityA")
        .setLongLabel("打開ActivityA_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
        .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityA"))
        .build();

ShortcutInfo shortcutB = new ShortcutInfo.Builder(this, "id2")
        .setShortLabel("打開ActivityB")
        .setLongLabel("打開ActivityB_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_2))
        .setIntent(new Intent(Intent.ACTION_VIEW)
                .setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityB"))
        .build();

// 若不設置包名和打開Activity的路徑,此時快捷鍵將不知道具體打開哪個一個Activity,也就意味著該快捷鍵設置無效
ShortcutInfo shortcutC = new ShortcutInfo.Builder(this, "id3")
        .setShortLabel("未定義Activity")
        .setLongLabel("未定義Activity_Long")
        .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
        .setIntent(new Intent(Intent.ACTION_VIEW))
        .build();

shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutA, shortcutB, shortcutC));

這裡寫圖片描述

設置rank

    ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

    ShortcutInfo shortcutC = new ShortcutInfo.Builder(this, "id1")
            .setShortLabel("打開ActivityC")
            .setLongLabel("打開ActivityC_Long")
            .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
            .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityC"))
            .build();

    ShortcutInfo shortcutD = new ShortcutInfo.Builder(this, "id2")
            .setShortLabel("打開ActivityD")
            .setLongLabel("打開ActivityD_Long")
            .setRank(0)
            .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_2))
            .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityD"))
            .build();

    ShortcutInfo shortcutE = new ShortcutInfo.Builder(this, "id3")
            .setShortLabel("打開ActivityE")
            .setLongLabel("打開ActivityE_Long")
            .setRank(0)
            .setIcon(Icon.createWithResource(mContext, R.mipmap.ic_1))
            .setIntent(new Intent(Intent.ACTION_VIEW).setClassName("com.example.tea.appshortcutsdemo", "com.example.tea.appshortcutsdemo.ActivityE"))
            .build();

    shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutC, shortcutD, shortcutE));

這裡寫圖片描述

從未設置rank和設置rank,可以清晰的看出動態設置的快捷鍵的顯示的順序。當未設置rank時,根據添加至快捷鍵列表的先後順序顯示。當設置rank時,設置rank的顯示優先級高於未設置的快捷鍵。如果設置相同的rank,顯示優先級根據設置的先後順序。

系統會自動調整排名,以便每個類別(動態或清單)中的每個目標活動都是唯一的。例如,如果有3個動態快捷鍵排名為0,1和2,則添加排名為1的另一個動態快捷鍵表示將此快捷鍵放置在第二個位置的請求。作為響應,第三和第四快捷鍵移動靠近快捷鍵列表的底部,它們的等級分別改變為2和3。

清單快捷鍵和動態快捷鍵組合

清單快捷鍵和動態快捷鍵均不設置rank

這裡寫圖片描述

動態快捷鍵設置rank

這裡寫圖片描述

從各個情況的效果圖上,我們可以得出快捷鍵的顯示順序規則:

清單快捷鍵永遠優於動態快捷鍵 設置rank屬性調整快捷鍵顯示順序的優先級,其僅有效於其所屬的類別(動態或清單),清單或者動態的rank值是相對獨立的. 不管是否設置了rank還是設置了rank,系統會自動調整排名,當其rank值相同時,會以先後順序作為基准點派尋

備份還原

如果應用清單文件中設置android:allowBackup =“true”,當前應用支持用戶在更改設備時備份和還原應用。對於快捷鍵來說,只有固定的快捷鍵會自動回復,但是系統不會備份固定快捷鍵相關聯的圖標。所以,快捷鍵相關的圖標應保存在應用程序中。

在用戶重新安裝應用程序時,會自動重新發布清單快捷鍵,但是動態快捷需要在相關邏輯或者操作下重新發布。

結束語

Android 7.1的Shortcut還是給人耳目一新的感覺,使用起來的有點小爽。美中不足的是,其要求SDK在版本在25以上才可以使用。較國內手機系統版本相比,此功能普及還是需要一段時間,強烈建議google將其加入support包內,以便大眾使用。在這裡我先爽了~~~如果有想感受的,趕緊裝個7.1的虛擬機。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved