Android - 應用內頁面跳轉設計與六種常用的頁面跳轉實踐

1. 應用內頁面跳轉設計

應用頁面跳轉與應用的用戶體驗有直接相關。

如果應用爲了看一個詳情,跳轉了大於3個界面,就很大可能流失用戶和被用戶吐槽,更不用說,跳進去又退出大於3個界面纔回到主界面。

應用頁面的跳轉往往隨着應用變大,頁面增多,界面跳轉出現的 bug 也就隨之增多。應用頁面跳轉我建議縱向深度不超過3層,最多3層即可; 如果項目過大,可分爲子模塊主界面,後分散界面,具體怎麼跳轉需要按需求而定。但常用的跳轉方式不外乎是一樣的。

比如,我常用的六種跳轉方式 : (如圖所示)

這裏寫圖片描述

六種跳轉方式,我將分爲兩大類進行說明:

  • 應用 task - 子模塊 task - 頁面
  • 應用 task - 頁面

2. 應用 task - 子模塊 task - 頁面

一個 app 中所有的 activity 默認都爲名稱爲包名affinity,爲應用 task 堆棧 ;但並不能說明一個 app 只有一個 task 堆棧 。

使用 taskaffinityintent 中的 FLAG_ACTIVITY_NEW_TASK 開啓新的 task 堆棧

開啓新的 task 開啓方式:

1. android:taskAffinity

設置 task affinity 名稱,建議爲 包名-模塊名-task

    <activity
            android:name=".OnePageActivity"
          android:taskAffinity="cn.labelnet.android.testtaskflag.onepagetask"
           />

2. 跳轉 activity

 private void moveNewTask(Class<?> cls) {
        Intent intent = new Intent(this, cls);
        // 設置 flag
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

3. 結果


cn.labelnet.android.testtaskflag E/LOG: Main Page >> task id : 756  |  root task : true
cn.labelnet.android.testtaskflag E/LOG: One Page >> task id : 757  |  root task : true
cn.labelnet.android.testtaskflag E/LOG: Two Page >> task id : 757  |  root task : false

如日誌所示 main 任務棧 taskId 爲 756 ,而在打開 onePage 的時候,任務棧 taskId 爲 757;
而在 onePage 的基礎上打開 twoPagetaskId 也爲757 , 說明 twoPage 被加入了 OnePage的任務棧中。

網上有說不需要在intentadd FLAG_ACTIVITY_NEW_TASK flag 也可以,如下所示:

// 經過測試,在 android 5.1(沒測其他版本) 上是不可以開啓新的堆棧 task 
  <activity
            android:name=".OnePageActivity"
            android:allowTaskReparenting="true"
            android:taskAffinity="cn.labelnet.android.testtaskflag.onepagetask" />

其實

如果考慮到頁面重用,最佳的選擇是在 intent 中 添加 flag 是最靈活的使用;


2.1 應用 task - 子模塊 task 說明

可以將項目中的模塊放在一起,假如爲 module main , 頁面跳轉流程爲:

打開應用 -> 主界面 -> module main 入口 -> module main

module main 方便管理頁面堆棧,所以爲 module mian 開啓子 task 堆棧;

建議將 model main 設置 launchMode 設置爲 singleTop

  <activity
            android:name=".OnePageActivity"
            android:launchMode="singleTop"
            android:taskAffinity="cn.labelnet.android.testtaskflag.onepagetask" />

獲取通過 intent 設置爲 singleTop

 private void moveNewTask(Class<?> cls) {
        Intent intent = new Intent(this, cls);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);
    }

2.2 Mode 1

頁面流程 :

打開應用 -> 主界面 -> module main 入口 -> module main -> page1 -> page2

頁面返回 : 模塊內上一頁

這裏寫圖片描述

實現 : 在 page2 中 直接重寫

 @Override
    public void onBackPressed() {
        // 調用 finish 
        finish();
    }

2.3 mode 2

頁面流程 :

打開應用 -> 主界面 -> module main 入口 -> module main -> page1 -> page2

頁面返回 : module main 模塊主界面

這裏寫圖片描述

module main launchMode 支持 :

  • singletop
  • singletask
  • standard
  • 不設置

實現:在 page 2 中 重寫

 @Override
    public void onBackPressed() {
        // 調用 finish Affinity
        finishAffinity();
    }

2.4 mode 3

頁面流程 :

打開應用 -> 主界面 -> module main 入口 -> module main -> page1 -> page2

頁面返回 : main 應用主界面

這裏寫圖片描述

實現 :

首先確定你的 module mainlaunchMode 爲下面支持的

module main launchMode 支持 :

  • singletop
  • singletask
  • standard
  • 不設置

基本流程:

  • 通過 intentFLAG_ACTIVITY_CLEAR_TOP 進入 module main 清除 task 堆棧的所有 activity
  • module main 中進行 finish() 即可;

具體實現:

在 page 2 中使用 startactivity , 如果 module mainsingle top 模式 ,所有會執行 activity 中的 onNewIntent 方法,然後傳入參數,finish 即可;如果 module main 不是 single top 模式,需要自己設置

page 2 實現:

 private void moveNewTask(Class<?> cls) {
        Intent intent = new Intent(this, cls);
        intent.putExtra("key", "finish");
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        //如果不是 single top 模式
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);
    }

 @Override
 public void onBackPressed() {
        // module main
        moveNewTask(OnePageActivity.class);
  }

module main 實現 :

 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (intent != null) {
            if (intent.hasExtra("key")) {
                Log.e("LOG", "onNewIntent Value : " + intent.getStringExtra("key"));
                if (intent.getStringExtra("key").equals("finish")) {
                    finish();
                }
            }
        }
    }

3. 應用 task - 頁面

基本的頁面跳轉還是上面的常用的內容,通過 intentflagfinish 進行控制;由於只有一個 應用 task 堆棧,所以在沒有設置任何 android:taskAffinity 情況下不能使用 finishAffinity 否則會退出 app ;通過 android:taskAffinityfinishAffinity 結合也可以進行配合頁面跳轉;

3.1 mode 4

基本界面流程:

主界面 -> page1 -> page2 -> page 3

頁面返回流程:

這裏寫圖片描述

實現: 在 page 3 中 重寫實現,簡單的堆棧問題

 @Override
    public void onBackPressed() {
        finish();
    }

3.2 mode 5

基本界面流程:

主界面 -> page1 -> page2 -> page 3

頁面返回流程:

這裏寫圖片描述

兩種方式實現:

方式 1 :

page 1 中設置 android:taskAffinity 屬性

  <activity android:name=".OnePageActivity"
            android:taskAffinity="cn.labelnet.task2"/>

在 page 3 中 進行執行

@Override
    public void onBackPressed() {
        finishAffinity();
    }

方式 2 :

前提 :

根據需求設置 page 1launchModesingle top 模式,不是需要手動設置;
比如順序填寫資料,完成確定後,返回用戶資料等;

page 3 中 實現:

 private void moveNewTask(Class<?> cls) {
        Intent intent = new Intent(this, cls);
        intent.putExtra("key", "value");
        // 設置這個將 cls 上面的堆棧信息清除掉
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        // 設置返回的 activtiy 未 single top 模式,即不刷新頁面
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);
    }

@Override
public void onBackPressed() {
        moveNewTask(OnePageActivity.class);
}

可以在 page 1 中獲取到回調信息 重寫 onNewIntent()方法:

 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (intent != null) {
            if (intent.hasExtra("key")) {
                Log.e("LOG", "onNewIntent Value : " + intent.getStringExtra("key"));
            }
        }
    }

3.3 mode 6

基本界面流程:

主界面 -> page1 -> page2 -> page 3

頁面返回流程:

這裏寫圖片描述

實現方式和 mode 5 兩種方式一樣,但建議 :

  • app 主頁 main 設置 android:taskAffinity , 這樣可以在任何界面通過 finishAffinity(); 即可完成返回
  • 非主頁 建議使用方式2 ,畢竟使用完畢要通過 finish() 進行銷燬,而 app main 不能銷燬!

4. 總結

  • Main : 設置 android:taskAffinity , 通過 finishAffinity 返回 main
  • Module main : 開啓 子 task 堆棧管理模塊頁面,finish 返回 main
  • Intent.FLAG_ACTIVITY_NEW_TASKIntent.FLAG_ACTIVITY_CLEAR_TOP

5. 測試 BaseActivity 類

package cn.labelnet.android.testtaskflag;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

/**
 * Created by yuan on 21/06/2017.
 */

public abstract class BaseActivity extends AppCompatActivity {


    protected abstract String getLogTitle();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        printLog("onCreate");
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        printLog("onPostCreate");
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        printLog("onPostResume");
    }

    @Override
    protected void onStart() {
        super.onStart();
        printLog("onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        printLog("onResume");
        Log.e("LOG", getLogTitle() + " >> task id : " + this.getTaskId() + "  |  root task : " + this.isTaskRoot());
    }

    @Override
    protected void onPause() {
        super.onPause();
        printLog("onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        printLog("onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        printLog("onDestroy");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        printLog("onRestart");
    }

    private void printLog(String status) {
        Log.v("LOG", getLogTitle() + " >>  " + status);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章