Android進階;Activity的棧與跳轉(筆記)

安卓開發高階技術分享發表於2019-01-18

Activity是Android四大元件中用來顯示介面和操作互動的,一般來說,我們手機上都會開啟多個App,每個App又有多個Activity,在使用者看來,這些Activity的建立、回退、跳轉、複用等,都是使用者體驗,甚至是業務邏輯的一部分,所以Android提供了完備的管理機制。
先來梳理一下基礎知識。

Process、AMS、ActivityStack、ActivityTask

  • Process,系統為App提供的程式(Process)資源,預設一個App一個Process,我們也可以要求為一個App提供多個Process。
  • AMS,系統開機啟動時,會啟動ActivityManagerService(簡稱AMS)來管理四大元件以及Intent、pendingintent、apk程式、task和釋放元件記憶體等。AMS是一個獨立的程式(SystemServie、AMS、PMS、WMS等系統服務,實質都是一個個App,各自擁有自己的程式),系統只有一個AMS,而且因為AMS在獨立的程式上,所以AMS和App之間,需要通過IPC機制進行跨程式通訊。
  • ActivityStack ,AMS為了管理Activity例項,會建立並管理一個ActivityStack,用ActivityStackSupervisor來更新這個棧,因為系統只有一個AMS,所以ActivityStack也只有一個。ActivityStack是一個管理者的角色,會管理協調ActivityRecord和TaskRecord,以及所有的任務棧。
  • ActivityTask,系統中的所有Activity,在面向使用者時可能分成多個組,這是按照任務棧(Task)來組織的,我們常說的Activity啟動模式,其實是操作任務棧(Task),而不是操作Activity棧(Stack)

組織形式大概是這樣的:

 

 

 

(我們可以用gethashcode()獲取Activity例項的唯一標識、用gettaskaffinity()獲取Activity所在的任務棧,用adb shell dumpsys activity命令可以列出所有的Activity)

可見,Activity管理的核心在於AMS,AMS中分兩個維度來管理Activity,一個是ActivityStack,只有一個,用ActivityRecord來記錄對應的Activity資訊,主要用來管理系統中有哪些Activity;另一個是ActivityTask,可能有多個,用TaskRecord來記錄對應的Activity資訊,主要用來把Activity組合成為多個Task棧,以便按照特定的業務邏輯展示給使用者。
所以,要管理多個Activity之間的關係,主要依靠任務棧Task。

任務棧(Task)

 

 

長按Home鍵(有的裝置是長按選單鍵),那些最近開啟的App記錄,就是任務棧Task。

 

 

Task任務棧也叫BackStack回退棧,是後進先出棧,在一個Task棧裡一直按Back鍵,就會不斷回退到上一個Activity(包括其他App的Activity),直到回退至Home,所以,使用者感知到的Activity介面回退邏輯,是由Task棧決定的,管理Activity的回退跳轉邏輯,其實就是管理Task任務棧。
Task不止一個,我們有可能會把現有的Task整體移動到後臺,然後建立一個新的Task,點開Notification、點選Home鍵(或在Activity中呼叫moveTaskToBack(true),false值表示當前Activity必須在棧底)、App建立NewTask等行為,都可能把Task移動到後臺,建立新的Task。
對Task任務棧的管理,主要包括Activity啟動模式和IntentFlag建立方式兩部分。

Activity的四種啟動模式

啟動Activity的重點在於,如何複用已經存在的Activity例項,所以四種啟動模式實際上是四種複用模式,針對複用策略,Android中定義了四種啟動模式(android:launchMode):

  • "standard",預設,不復用,每次建立新例項。
  • "singleTop",棧頂複用,檢查棧頂,如果不是要啟動的Activity,建立新例項;如果是,就複用。
  • "singleTask",棧中複用,檢查任務棧,如果沒有要啟動的Activity,建立新例項;如果有,就把該Activity上方的其他Activity全部推出任務棧,複用該Activity。
  • "singleInstance",單例模式,獨享一個任務棧,且只有一個任務棧,只有
    一個Activity例項。

這四種啟動模式可以在manifest檔案中定義,也可以在intent中用程式碼動態賦值(例如新增FLAG_ACTIVITY_SINGLE_TOP標識,等同於設定singleTop屬性)。
這四種模式中,standard和singleTop型別的Activity可能出現多個例項,singleTask和singleInstance型別則只能有一個例項。
如果要使用startActivityForResult,在5.0以前還有使用限制,只允許standard<->singleTop、singleTask->standard、singleTask->singleTop,其他跳轉因為無法確保回到原Activity,可能會遇到RESULT_CANCELD問題導致無法接收返回值。

 

這四種模式大概可以這樣表示:

 


如果Activity被複用了,就會回撥onNewIntent()函式。
正常啟動的Activity生命週期是onCreate()-->onStart()-->onResume()...。
複用的Activity生命週期是onNewIntent()-->onResart()-->onStart()--> onResume()...

一些常見的IntentFlag

除了上一節的四種啟動模式之外,我們還可以在程式碼中設定intentFlag,用更豐富的形式來定義Activity的建立和複用策略。
intentFlag有時候需要和taskAffinity屬性(android:taskAffinity)配合使用,taskAffinity指的是Activity的任務親和性,即Activity與哪個Task更親和,預設值是應用的包名,taskAffinity屬性在2種情況下起作用:啟動 activity的Intent物件新增了FLAG_ACTIVITY_NEW_TASK標記,或activity的allowTaskReparenting屬性為true。
一些常見的IntentFlag如下:

  • FLAG_ACTIVITY_NEW_TASK (預設)
    其實這種標識下,系統會根據Activity的taskAffinity去建立一個新的Task任務棧,並向任務棧中壓入一個新建立的Activity例項。
    不過,一般情況下App中的taskAffinity都是同一個預設值(包名),這個Task已經存在了,這樣的話,執行效果就相當於standard啟動模式,在已有的Task中壓入一個新建的Activity。
    還需要說明的是,如果要用startActivityForResult的形式來調起新的Activity並等待返回結果,就不能使用FLAG_ACTIVITY_NEW_TASK標記,否則呼叫方的Activity可能會立即收到onActivityResult,實際上就是回撥失效了。這是因為使用startActivityForResult時,兩個Activity需要在同一個Task裡,Android認為不同Task之間的Activity是不能傳遞資料的。
  • FLAG_ACTIVITY_SINGLE_TOP
    相當於singleTop啟動模式。
  • FLAG_ACTIVITY_CLEAR_TOP
    模式情況下,會把目標Activity頂部的所有Activity都銷燬,同時連同目標Activity也銷燬,然後重建目標Activity。
    如果和FLAG_ACTIVITY_SINGLE_TOP一起使用,即:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

就會複用目標Activity,這時相當於singleTask啟動模式(CLEAR_TOP這個名字也揭示了singleTask的實質)。
FLAG_ACTIVITY_CLEAR_TOP往往和FLAG_ACTIVITY_NEW_TASK一起使用。用2個標記可以定位已存在的activity並讓它處於可以響應intent的位置。

  • FLAG_ACTIVITY_CLEAR_TASK
    清空目標TASK,把新建的Activity作為棧底的Activity,必須與FLAG_ACTIVITY_NEW_TASK一起使用。
  • FLAG_ACTIVITY_REORDER_TO_FRONT
    如果Task中已經有例項,把該例項挪到棧頂。(優先順序低於FLAG_ACTIVITY_CLEAR_TOP)。
  • FLAG_ACTIVITY_BROUGHT_TO_FRONT
    這個標誌一般不是由程式程式碼設定的,而是在launchMode中設定singleTask模式時系統幫你設定。
  • FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    任務重置,在Activity導致新建Task或挪動到Task頂部時使用。
  • FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
    為Task設定一個還原點,當Task恢復到前臺時,找到有這個屬性的Activity,把這個Activity頂部的其他Activity,連同這個Activity一起銷燬。
  • FLAG_ACTIVITY_MULTIPLE_TASK
    Android系統為了節省資源,預設是複用Activity的,在開啟Activity時,總是先搜尋存在的task棧,去尋找匹配intent的一個activity。
    但是,如果使用了FLAG_ACTIVITY_MULTIPLE_TASK標識(和FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用),就會跳過複用搜尋步驟,直接建立一個新的task棧,並且在裡面啟動新的activity。
  • FLAG_ACTIVITY_NO_USER_ACTION,使用者行為標識,用來區分離開當前Activity是使用者行為還是系統行為(比如呼入電話,會導致當前Activity退至後臺,但這不是使用者行為),如果不是使用者行為,就不會執行生命週期中的onUserLeaveHint(),這樣我們可以知道使用者有沒有做某些操作(比如是否看到了推送的通知)。
  • FLAG_ACTIVITY_NO_ANIMATION
    Activity切換時不展示動畫。

其他一些與棧相關的Activity屬性:

  • android:taskAffinity
    親和性,在intentFlag標識中和FLAG_ACTIVITY_NEW_TASK一起作用;或者與android:allowTaskReparenting共同起作用。
  • android:allowTaskReparenting
    允許重排任務棧,就是說Activity可以更換所在的Task任務棧,Activity可能在TaskA中,此時系統把一個TaskB移動到前臺,如果TaskA和TaskB的affinity相同,那麼Activity就會被挪到TaskB。
  • android:excludeFromRecents
    Activity不新增到最近開啟的應用列表中。
  • android:alwaysRetainTaskState
    儲存Task棧中的Activity,當Task被移動到後臺後,如果長期沒有使用,Android可能會去回收記憶體,僅保留棧底的Activity,其他Activity全部回收掉,如果alwaysRetainTaskState屬性為true,系統就不會進行回收。
  • android:clearTaskOnLaunch
    催促回收Task棧(與alwaysRetainTaskState相反),這個屬性會被賦給棧底的Activity,一旦使用者離開Task,系統就會立即回收棧中的Activity,僅保留棧底的Activity。
  • android:finishOnTaskLaunch
    催促回收Activity,被賦予這個屬性的Activity,一旦使用者退出Task,Activity就會立即被系統回收,Task中不再保留這個Activity,如果恰好是棧底Activity,那麼Task也就清空了。
  • android:noHistory
    清空歷史,離開Activity後,立即回收Activity,Task任務棧中不儲存該Activity。noHistory和finishOnTaskLaunch的區別在於銷燬Activity的時機,noHistory是在離開Activity時銷燬,finishOnTaskLaunch是在切換Task時銷燬。

Scheme跳轉(頁面內跳轉)

我們知道,Activity跳轉是通過Intent來實現的,在定義Intent時,有三種形式:

  • 類名
    定義intent時設定目標Activity的類名
    intent.setClass(context,ActivityA.class);
    setClass其實就是setComponent,相當於
    intent.setComponent(new ComponentName(context, ActivityA.class));
  • Action
    需要在manifest中定義action
    <intent-filter> <action android:name="your.action.name" />
    定義intent時設定Action
    intent.setAction(your.action.name);
  • Scheme
    需要在manifest中定義scheme
    定義intent時設定url
    new Intent(Intent.ACTION_VIEW, Uri.parse(Url) )

在這三種形式中,Scheme是最靈活,適用最廣的,因為只需要一個url,就可以實現跳轉。
Scheme是一種頁面內跳轉協議,在Android和IOS都有使用,Activity向系統註冊URL Scheme,就可以通過特定的URL,直接開啟App中的某些頁面,常用於支援以下幾種場景:

  • 伺服器下發跳轉路徑,客戶端根據伺服器下發跳轉路徑,建立Intent,(new Intent(Intent.ACTION_VIEW, Uri.parse(Url) ) ) ,實現跳轉;
  • Web頁面點選,根據具體跳轉路徑判斷,如果(url.indexOf(H5Constant.SCHEME) != -1),就去建立Intent,(Intent intent = new Intent(Intent.ACTION_VIEW, uri) ) ,實現跳轉;
  • App端收到伺服器端下發的通知,從訊息中解析NotifeConstant.VALID_ACTION_URL得到URL,然後建立Intent,(Intent intent =H5Constant.buildSchemeFromUrl(Url)),實現跳轉。

Scheme協議中,URL的格式為:
[scheme:][//domain][:port][path][?query params][#fragment]
其中,scheme、domain、path都需要在manifest中定義。

<activity android:name=".TargetActivity">
   <intent-filter>
     <action android:name="android.intent.action.VIEW"/>
     <category android:name="android.intent.category.DEFAULT"/>
     <!--允許從瀏覽器開啟App-->
     <category android:name="android.intent.category.BROWSABLE"/>
     <!--可以定義多組scheme,多個URL指向同一個Activity-->
     <data android:scheme="biz1" 
        android:host="com.buy"
        android:path="/path"/>
     <data android:scheme="biz2"
       android:host="com.earn"
       android:path="/route"/>
   </intent-filter>
</activity>

被啟動的Activity可以從Intent中找到URL中的值

Intent intent = getIntent();    
String scheme = intent.getScheme();    
Uri uri = intent.getData();   
String tab= uri.getQueryParameter("your param"); 

Activity是Android四大元件中用來顯示介面和操作互動的,一般來說,我們手機上都會開啟多個App,每個App又有多個Activity,在使用者看來,這些Activity的建立、回退、跳轉、複用等,都是使用者體驗,甚至是業務邏輯的一部分,所以Android提供了完備的管理機制。
先來梳理一下基礎知識。

Process、AMS、ActivityStack、ActivityTask

  • Process,系統為App提供的程式(Process)資源,預設一個App一個Process,我們也可以要求為一個App提供多個Process。
  • AMS,系統開機啟動時,會啟動ActivityManagerService(簡稱AMS)來管理四大元件以及Intent、pendingintent、apk程式、task和釋放元件記憶體等。AMS是一個獨立的程式(SystemServie、AMS、PMS、WMS等系統服務,實質都是一個個App,各自擁有自己的程式),系統只有一個AMS,而且因為AMS在獨立的程式上,所以AMS和App之間,需要通過IPC機制進行跨程式通訊。
  • ActivityStack ,AMS為了管理Activity例項,會建立並管理一個ActivityStack,用ActivityStackSupervisor來更新這個棧,因為系統只有一個AMS,所以ActivityStack也只有一個。ActivityStack是一個管理者的角色,會管理協調ActivityRecord和TaskRecord,以及所有的任務棧。
  • ActivityTask,系統中的所有Activity,在面向使用者時可能分成多個組,這是按照任務棧(Task)來組織的,我們常說的Activity啟動模式,其實是操作任務棧(Task),而不是操作Activity棧(Stack)

組織形式大概是這樣的:

 

組織形式

 

(我們可以用gethashcode()獲取Activity例項的唯一標識、用gettaskaffinity()獲取Activity所在的任務棧,用adb shell dumpsys activity命令可以列出所有的Activity)

可見,Activity管理的核心在於AMS,AMS中分兩個維度來管理Activity,一個是ActivityStack,只有一個,用ActivityRecord來記錄對應的Activity資訊,主要用來管理系統中有哪些Activity;另一個是ActivityTask,可能有多個,用TaskRecord來記錄對應的Activity資訊,主要用來把Activity組合成為多個Task棧,以便按照特定的業務邏輯展示給使用者。
所以,要管理多個Activity之間的關係,主要依靠任務棧Task。

任務棧(Task)

 

 

長按Home鍵(有的裝置是長按選單鍵),那些最近開啟的App記錄,就是任務棧Task。

圖片來自Activity啟動模式圖文詳解

 

Task任務棧也叫BackStack回退棧,是後進先出棧,在一個Task棧裡一直按Back鍵,就會不斷回退到上一個Activity(包括其他App的Activity),直到回退至Home,所以,使用者感知到的Activity介面回退邏輯,是由Task棧決定的,管理Activity的回退跳轉邏輯,其實就是管理Task任務棧。
Task不止一個,我們有可能會把現有的Task整體移動到後臺,然後建立一個新的Task,點開Notification、點選Home鍵(或在Activity中呼叫moveTaskToBack(true),false值表示當前Activity必須在棧底)、App建立NewTask等行為,都可能把Task移動到後臺,建立新的Task。
對Task任務棧的管理,主要包括Activity啟動模式和IntentFlag建立方式兩部分。

Activity的四種啟動模式

啟動Activity的重點在於,如何複用已經存在的Activity例項,所以四種啟動模式實際上是四種複用模式,針對複用策略,Android中定義了四種啟動模式(android:launchMode):

  • "standard",預設,不復用,每次建立新例項。
  • "singleTop",棧頂複用,檢查棧頂,如果不是要啟動的Activity,建立新例項;如果是,就複用。
  • "singleTask",棧中複用,檢查任務棧,如果沒有要啟動的Activity,建立新例項;如果有,就把該Activity上方的其他Activity全部推出任務棧,複用該Activity。
  • "singleInstance",單例模式,獨享一個任務棧,且只有一個任務棧,只有
    一個Activity例項。

這四種啟動模式可以在manifest檔案中定義,也可以在intent中用程式碼動態賦值(例如新增FLAG_ACTIVITY_SINGLE_TOP標識,等同於設定singleTop屬性)。
這四種模式中,standard和singleTop型別的Activity可能出現多個例項,singleTask和singleInstance型別則只能有一個例項。
如果要使用startActivityForResult,在5.0以前還有使用限制,只允許standard<->singleTop、singleTask->standard、singleTask->singleTop,其他跳轉因為無法確保回到原Activity,可能會遇到RESULT_CANCELD問題導致無法接收返回值。

 

這四種模式大概可以這樣表示:

四種啟動模式


如果Activity被複用了,就會回撥onNewIntent()函式。
正常啟動的Activity生命週期是onCreate()-->onStart()-->onResume()...。
複用的Activity生命週期是onNewIntent()-->onResart()-->onStart()--> onResume()...

一些常見的IntentFlag

除了上一節的四種啟動模式之外,我們還可以在程式碼中設定intentFlag,用更豐富的形式來定義Activity的建立和複用策略。
intentFlag有時候需要和taskAffinity屬性(android:taskAffinity)配合使用,taskAffinity指的是Activity的任務親和性,即Activity與哪個Task更親和,預設值是應用的包名,taskAffinity屬性在2種情況下起作用:啟動 activity的Intent物件新增了FLAG_ACTIVITY_NEW_TASK標記,或activity的allowTaskReparenting屬性為true。
一些常見的IntentFlag如下:

  • FLAG_ACTIVITY_NEW_TASK (預設)
    其實這種標識下,系統會根據Activity的taskAffinity去建立一個新的Task任務棧,並向任務棧中壓入一個新建立的Activity例項。
    不過,一般情況下App中的taskAffinity都是同一個預設值(包名),這個Task已經存在了,這樣的話,執行效果就相當於standard啟動模式,在已有的Task中壓入一個新建的Activity。
    還需要說明的是,如果要用startActivityForResult的形式來調起新的Activity並等待返回結果,就不能使用FLAG_ACTIVITY_NEW_TASK標記,否則呼叫方的Activity可能會立即收到onActivityResult,實際上就是回撥失效了。這是因為使用startActivityForResult時,兩個Activity需要在同一個Task裡,Android認為不同Task之間的Activity是不能傳遞資料的。
  • FLAG_ACTIVITY_SINGLE_TOP
    相當於singleTop啟動模式。
  • FLAG_ACTIVITY_CLEAR_TOP
    模式情況下,會把目標Activity頂部的所有Activity都銷燬,同時連同目標Activity也銷燬,然後重建目標Activity。
    如果和FLAG_ACTIVITY_SINGLE_TOP一起使用,即:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

就會複用目標Activity,這時相當於singleTask啟動模式(CLEAR_TOP這個名字也揭示了singleTask的實質)。
FLAG_ACTIVITY_CLEAR_TOP往往和FLAG_ACTIVITY_NEW_TASK一起使用。用2個標記可以定位已存在的activity並讓它處於可以響應intent的位置。

  • FLAG_ACTIVITY_CLEAR_TASK
    清空目標TASK,把新建的Activity作為棧底的Activity,必須與FLAG_ACTIVITY_NEW_TASK一起使用。
  • FLAG_ACTIVITY_REORDER_TO_FRONT
    如果Task中已經有例項,把該例項挪到棧頂。(優先順序低於FLAG_ACTIVITY_CLEAR_TOP)。
  • FLAG_ACTIVITY_BROUGHT_TO_FRONT
    這個標誌一般不是由程式程式碼設定的,而是在launchMode中設定singleTask模式時系統幫你設定。
  • FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    任務重置,在Activity導致新建Task或挪動到Task頂部時使用。
  • FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
    為Task設定一個還原點,當Task恢復到前臺時,找到有這個屬性的Activity,把這個Activity頂部的其他Activity,連同這個Activity一起銷燬。
  • FLAG_ACTIVITY_MULTIPLE_TASK
    Android系統為了節省資源,預設是複用Activity的,在開啟Activity時,總是先搜尋存在的task棧,去尋找匹配intent的一個activity。
    但是,如果使用了FLAG_ACTIVITY_MULTIPLE_TASK標識(和FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用),就會跳過複用搜尋步驟,直接建立一個新的task棧,並且在裡面啟動新的activity。
  • FLAG_ACTIVITY_NO_USER_ACTION,使用者行為標識,用來區分離開當前Activity是使用者行為還是系統行為(比如呼入電話,會導致當前Activity退至後臺,但這不是使用者行為),如果不是使用者行為,就不會執行生命週期中的onUserLeaveHint(),這樣我們可以知道使用者有沒有做某些操作(比如是否看到了推送的通知)。
  • FLAG_ACTIVITY_NO_ANIMATION
    Activity切換時不展示動畫。

其他一些與棧相關的Activity屬性:

  • android:taskAffinity
    親和性,在intentFlag標識中和FLAG_ACTIVITY_NEW_TASK一起作用;或者與android:allowTaskReparenting共同起作用。
  • android:allowTaskReparenting
    允許重排任務棧,就是說Activity可以更換所在的Task任務棧,Activity可能在TaskA中,此時系統把一個TaskB移動到前臺,如果TaskA和TaskB的affinity相同,那麼Activity就會被挪到TaskB。
  • android:excludeFromRecents
    Activity不新增到最近開啟的應用列表中。
  • android:alwaysRetainTaskState
    儲存Task棧中的Activity,當Task被移動到後臺後,如果長期沒有使用,Android可能會去回收記憶體,僅保留棧底的Activity,其他Activity全部回收掉,如果alwaysRetainTaskState屬性為true,系統就不會進行回收。
  • android:clearTaskOnLaunch
    催促回收Task棧(與alwaysRetainTaskState相反),這個屬性會被賦給棧底的Activity,一旦使用者離開Task,系統就會立即回收棧中的Activity,僅保留棧底的Activity。
  • android:finishOnTaskLaunch
    催促回收Activity,被賦予這個屬性的Activity,一旦使用者退出Task,Activity就會立即被系統回收,Task中不再保留這個Activity,如果恰好是棧底Activity,那麼Task也就清空了。
  • android:noHistory
    清空歷史,離開Activity後,立即回收Activity,Task任務棧中不儲存該Activity。noHistory和finishOnTaskLaunch的區別在於銷燬Activity的時機,noHistory是在離開Activity時銷燬,finishOnTaskLaunch是在切換Task時銷燬。

Scheme跳轉(頁面內跳轉)

我們知道,Activity跳轉是通過Intent來實現的,在定義Intent時,有三種形式:

  • 類名
    定義intent時設定目標Activity的類名
    intent.setClass(context,ActivityA.class);
    setClass其實就是setComponent,相當於
    intent.setComponent(new ComponentName(context, ActivityA.class));
  • Action
    需要在manifest中定義action
    <intent-filter> <action android:name="your.action.name" />
    定義intent時設定Action
    intent.setAction(your.action.name);
  • Scheme
    需要在manifest中定義scheme
    定義intent時設定url
    new Intent(Intent.ACTION_VIEW, Uri.parse(Url) )

在這三種形式中,Scheme是最靈活,適用最廣的,因為只需要一個url,就可以實現跳轉。
Scheme是一種頁面內跳轉協議,在Android和IOS都有使用,Activity向系統註冊URL Scheme,就可以通過特定的URL,直接開啟App中的某些頁面,常用於支援以下幾種場景:

  • 伺服器下發跳轉路徑,客戶端根據伺服器下發跳轉路徑,建立Intent,(new Intent(Intent.ACTION_VIEW, Uri.parse(Url) ) ) ,實現跳轉;
  • Web頁面點選,根據具體跳轉路徑判斷,如果(url.indexOf(H5Constant.SCHEME) != -1),就去建立Intent,(Intent intent = new Intent(Intent.ACTION_VIEW, uri) ) ,實現跳轉;
  • App端收到伺服器端下發的通知,從訊息中解析NotifeConstant.VALID_ACTION_URL得到URL,然後建立Intent,(Intent intent =H5Constant.buildSchemeFromUrl(Url)),實現跳轉。

Scheme協議中,URL的格式為:
[scheme:][//domain][:port][path][?query params][#fragment]
其中,scheme、domain、path都需要在manifest中定義。

<activity android:name=".TargetActivity">
   <intent-filter>
     <action android:name="android.intent.action.VIEW"/>
     <category android:name="android.intent.category.DEFAULT"/>
     <!--允許從瀏覽器開啟App-->
     <category android:name="android.intent.category.BROWSABLE"/>
     <!--可以定義多組scheme,多個URL指向同一個Activity-->
     <data android:scheme="biz1" 
        android:host="com.buy"
        android:path="/path"/>
     <data android:scheme="biz2"
       android:host="com.earn"
       android:path="/route"/>
   </intent-filter>
</activity>

被啟動的Activity可以從Intent中找到URL中的值

Intent intent = getIntent();    
String scheme = intent.getScheme();    
Uri uri = intent.getData();   
String tab= uri.getQueryParameter("your param"); 

附錄;

附錄一;Android高階技術大綱

附錄二;Android進階實戰技術視訊

 

獲取方式;

加Android進階群;701740775。即可前往免費領取。麻煩備註一下csdn領取資料

 

相關文章