Android LaunchMode案例篇

來源:互聯網
上載者:User

標籤:star   pre   element   ons   stand   共用   通過   關閉   img   

首先感謝小夥伴的關注。然後祝願廣大的情侶們節日快樂!


在開發中有時會遇到這種情境,使用者點擊注冊。第一步,第二步,完畢注冊跳轉到登入介面,不須要使用者一步一步的返回到登入介面。這是怎麼實現的呢?
案例:有四個介面 A。B,C。D 從A跳轉到B。B跳轉到C,C跳轉到D,D完畢注冊跳轉到A,點擊返回鍵退出程式。詳細過程來看:

這裡提供了三種常見的解決方式。

方案一

1.資訊清單檔(AndroidManifest.xml)檔案設定A的啟動模式

        <activity android:name=".A"            android:launchMode="singleTask">

2.在D檔案:

 startActivity(new Intent(D.this, A.class));
方案二

使用 Intent 標誌。在D檔案:

        Intent intent =new Intent(D.this, A.class);        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);        startActivity(intent);        finish();
方案三

方案三相對於前面兩種方案略微麻煩一些。但更利於我們理解棧的原理。

1.建立ActivityManager類:

public class ActivityManager {    private static Stack<Activity> mStack;    private static ActivityManager mActivityManager;    public static ActivityManager getActivityManager() {        if (mActivityManager == null) {            mActivityManager = new ActivityManager();        }        return mActivityManager;    }    //將當前Activity推入棧中    public void pushActivity(Activity activity) {        if (mStack == null) {            mStack = new Stack<Activity>();        }        mStack.add(activity);    }    //退出棧頂Activity    public void popActivity(Activity activity) {        if (activity != null) {            //在從自己定義集合中取出當前Activity時,也進行了Activity的關閉操作            activity.finish();            mStack.remove(activity);            activity = null;        }    }    //獲得當前棧頂Activity    public Activity currentActivity() {        Activity activity = null;        if (!mStack.empty())            activity = mStack.lastElement();        return activity;    }    //退出棧中 cls曾經的全部Activity    public void popAllActivityExceptOne(Class cls) {        while (true) {            Activity activity = currentActivity();            if (activity == null) {                break;            }            if (activity.getClass().equals(cls)) {                break;            }            popActivity(activity);        }    }    //擷取棧    public Stack<Activity> getStackActivity() {        if (mStack != null) {            return mStack;        }        return new Stack<Activity>();    }}

2.MyApplication檔案(記得在資訊清單檔裡聲明)

public class MyApplication extends Application {    public static ActivityManager activityManager = null;    @Override    public void onCreate() {        super.onCreate();        activityManager = ActivityManager.getActivityManager();    }    //擷取執行個體    public ActivityManager getActivityManager() {        return activityManager;    }}

3.BaseActivity檔案(公用Activity)

public class BaseActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ((MyApplication)getApplication()).getActivityManager().pushActivity(this);    }    @Override    public void onBackPressed() {        super.onBackPressed();      ((MyApplication)getApplication()).getActivityManager().popActivity(this);    }}

4.D檔案

 startActivity(new Intent(D.this, A.class));        ((MyApplication) getApplication()).getActivityManager().popAllActivityExceptOne(A.class);
LaunchMode

launchMode 屬性指明了 activity 啟動 task 的方式。 launchMode 屬性可設為四種啟動模式:

  • standard
  • singleTop
  • singleTask
  • singleInstance
standard

預設值。系統在啟動 activity 的 task 中建立一個新的 activity 執行個體。並把 intent 傳送路徑指向它。該 activity 能夠被執行個體化多次,各個執行個體能夠屬於不同的 task,一個 task 中也能夠存在多個執行個體。

singleTop

假設 activity 已經存在一個執行個體並位於當前 task 的棧頂,則系統會調用已有執行個體的onNewIntent()方法把 intent 傳遞給已有執行個體,而不是建立一個新的 activity 執行個體。activity 能夠被執行個體化多次,各個執行個體能夠屬於不同的 task。一個 task 中能夠存在多個執行個體(但僅當 back stack 頂的 activity 執行個體不是該 activity 的)。

比方。假定 task 的 back stack 中包括了根 activity A 和 activities B、C、D(順序是 A-B-C-D;D 在棧頂)。


這時過來一個啟動 D 的 intent。假設 D 的啟動模式是預設的”standard”,則會啟動一個新的執行個體。棧內容變為 A-B-C-D-D。
可是。假設 D 的啟動模式是”singleTop”。則已有的 D 執行個體會通過onNewIntent():接收這個 intent,由於該執行個體位於棧頂——棧中內容仍然維持 A-B-C-D 不變。當然,假設 intent 是要啟動 B 的。則 B 的一個新執行個體還是會增加棧中,即使 B 的啟動模式是”singleTop”也是如此。

singleTask

系統將建立一個新的 task,並把 activity 執行個體作為根放入其中。可是,假設 activity 已經在其他 task 中存在執行個體,則系統會通過調用事實上例的onNewIntent() 方法把 intent 傳給已有執行個體。而不是再建立一個新執行個體。 此 activity 同一時刻僅僅能存在一個執行個體。

也能夠這麼來理解, 假設 task 中不存在 activity 執行個體,則建立執行個體並壓入棧頂;假設存在 activity 執行個體並位於棧頂,則複用。假設存在 activity 執行個體並不位於棧頂。則清空 task 中 activity 執行個體之上的元素。使 activity 執行個體位於棧頂。

singleInstance

除了系統不會把其他 activity 放入當前執行個體所在的 task 之外,其他均與”singleTask”同樣。activity 總是它所在 task 的唯一成員;它所啟動的不論什麼 activity 都會放入其他 task 中。

舉個範例:假定 task 的 back stack 中包括了根 activity A 和 activities B、C、D(順序是 A-B-C-D;D 在棧頂),而且 activities B 的啟動預設設定為 singleInstance 。那麼他們的出棧順序為 D-C-A-B 。

Intent幾種常見的flags
  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

注意:假設 activity 同一時候設定了 launchMode 和 flags ,那麼 flags 優先順序大於 launchMode 。

我們這裡須要先來瞭解一下 屬性中的 taskAffinity:

taskAffinity

affinity 表示 activity 預期所處的 task 。 預設情況下。同一個應用中的全部 activity 都擁有同一個 affinity 值。

因此,同一個應用中的全部 activity 預設都期望位於同一個 task 中。 只是。你能夠改動 activity 預設的 affinity 值。 不同應用中的 activity 能夠共用同一個 affinity 值。同一個應用中的 activity 也能夠賦予不同的 task affinity 值。

你能夠用 元素的 taskAffinity 屬性改動 activity 的 affinity,taskAffinity 屬性是一個字串值。必須與 元素定義的包名稱保證唯一性,由於系統把這個包名稱用於標識應用的預設 task affinity 值。

  1. 依據affinity又一次為 activity 選擇宿主task(與allowTaskReparenting屬性配合工作)。
  2. 啟動一個 activity 過程中 Intent 使用了 FLAG_ACTIVITY_NEW_TASK 標記,依據 affinity 尋找或建立一個新的具有相應affinity的task。

預設情況下。一個應用內的全部 activity 都具有同樣的 affinity,都是從 application 繼承而來,而 application 預設的 affinity 是 manifest 檔案裡的包名。

我們也能夠在 manifest 檔案設定 taskAffinity 屬性值:

    package="com.github.ws.launchmodedemo">    <application        android:taskAffinity="com.grasp.demo"

也能夠單獨為某個 activity 設定 taskAffinity 屬性值。

FLAG_ACTIVITY_NEW_TASK

當Intent對象包括這個標記時,系統會尋找或建立一個新的 task 來放置目標 activity 。尋找時依據目標 activity 的taskAffinity 屬性進行匹配,假設找到一個 task 的 taskAffinity 與之同樣,就將目標 activity 壓入此 task 中。假設尋找無果,則建立一個新的 task,並將該 task 的 taskaffinity 設定為目標 activity 的 taskactivity。將目標 activity 放置於此 task。注意,假設同一個應用中 activity 的 taskaffinity 都使用預設值或都設定同樣值時。應用內的 activity 之間的跳轉使用這個標記是沒有意義的,由於當前應用 task 就是目標 activity 最好的宿主。我們來看看以下的這個範例:

錄製工具不是非常清晰,有些模糊了。


從其中非常明顯的看出。程式A中有(a。b介面)。程式B中也有(a。b介面)。在程式A的b介面跳轉到程式B的b介面:

        Intent intent=new Intent("com.github.ws.flagdemo.B");        startActivity(intent);

按Home鍵回到主屏。在主選單中啟動程式B;按Home鍵回到主屏,在主選單中啟動程式A。

我們發如今從程式A跳轉到程式B的b之後,b執行個體好像是嵌入到了程式A中,可是不影響程式B的正常執行。

然後我們改動一下跳轉的代碼:

  Intent intent=new Intent("com.github.ws.flagdemo.B");  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  startActivity(intent);

我們看到區別了吧。當我們再次啟動程式B時,並沒有顯示程式B的a介面,而是顯示了b介面,當我們程式B返回到a介面,再次開啟程式A,顯示的是A的b介面。

由此可見, FLAG_ACTIVITY_NEW_TASK應該這樣去理解:依據 activity affinity 推斷是否須要建立新的Task,然後再建立新的Activity執行個體放進去。

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_CLEAR_TOP表示啟動的 activity 會將 task 中位於其上的 activity 都強制出棧。使其自身位於棧頂。與Activity啟動模式中的 singleTask 同樣。

FLAG_ACTIVITY_SINGLE_TOP

當task中存在目標Activity執行個體而且位於棧的頂端時,不再建立一個新的,直接利用這個執行個體。與Activity啟動模式中的singleTop效果同樣。

由於篇幅原因。文章到這裡就結束了。希望看了上文,對你有所協助。

Android LaunchMode案例篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.