1. 應用內頁面跳轉設計
應用頁面跳轉與應用的用戶體驗有直接相關。
如果應用爲了看一個詳情,跳轉了大於3個界面,就很大可能流失用戶和被用戶吐槽,更不用說,跳進去又退出大於3個界面纔回到主界面。
應用頁面的跳轉往往隨着應用變大,頁面增多,界面跳轉出現的 bug
也就隨之增多。應用頁面跳轉我建議縱向深度不超過3層,最多3層即可; 如果項目過大,可分爲子模塊主界面,後分散界面,具體怎麼跳轉需要按需求而定。但常用的跳轉方式不外乎是一樣的。
比如,我常用的六種跳轉方式 : (如圖所示)
六種跳轉方式,我將分爲兩大類進行說明:
- 應用
task
- 子模塊task
- 頁面 - 應用
task
- 頁面
2. 應用 task
- 子模塊 task
- 頁面
一個 app
中所有的 activity
默認都爲名稱爲包名的 affinity
,爲應用 task
堆棧 ;但並不能說明一個 app
只有一個 task
堆棧 。
使用
taskaffinity
和intent
中的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
的基礎上打開 twoPage
的 taskId
也爲757 , 說明 twoPage
被加入了 OnePage
的任務棧中。
網上有說不需要在intent
中 add 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 main
的launchMode
爲下面支持的
module main launchMode 支持 :
- singletop
- singletask
- standard
- 不設置
基本流程:
- 通過
intent
的FLAG_ACTIVITY_CLEAR_TOP
進入module main
清除task
堆棧的所有 activity - 在
module main
中進行finish()
即可;
具體實現:
在 page 2 中使用 startactivity
, 如果 module main
是 single 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
- 頁面
基本的頁面跳轉還是上面的常用的內容,通過 intent
的 flag
和 finish
進行控制;由於只有一個 應用 task
堆棧,所以在沒有設置任何 android:taskAffinity
情況下不能使用 finishAffinity
否則會退出 app
;通過 android:taskAffinity
與 finishAffinity
結合也可以進行配合頁面跳轉;
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 1
的launchMode
是single 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_TASK
和Intent.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);
}
}