關于Android應用回到桌面會重復打開閃屏頁

現(xiàn)在存在有的時候發(fā)現(xiàn)回到桌面會重復打開閃屏頁,我研究了一下,有如下結果凭需。


重現(xiàn)方式:

用android的installer安裝打開閃屏頁,按Home鍵回到首頁俄讹,然后點擊launcher的圖標會再打開一個閃屏頁,根據(jù)這篇博客是因為再打開時候Intent多了一個Flag,Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
那為什么會多這個flag弥奸,而又為什么多了這個flag只祠,會重復多打開頁面枯怖,這就是我這篇文章要講的勒庄。
解決方案還是上面講的

if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)> 0) {
    /**為了防止重復啟動多個閃屏頁面**/
    finish();
    return;
}

桌面launcher的打開與Installer打開的不同

先說結論,installer打開多了一個intent.setPackage(packageName)
代碼在Launcher3军熏,抽出來就是

public static void startAppByLauncher(Context context, String packageName) {
     android.content.pm.PackageInfo pi = null;

    try {

        pi = context.getPackageManager().getPackageInfo(packageName, 0);

        Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);

        resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT) {

            resolveIntent.setPackage(pi.packageName);

        }

        List<ResolveInfo> apps = context.getPackageManager().queryIntentActivities(resolveIntent, 0);

        ResolveInfo ri = apps.iterator().next();

        if (ri != null) {

            String packageName1 = ri.activityInfo.packageName;

            String className = ri.activityInfo.name;

            Intent intent = new Intent(Intent.ACTION_MAIN);

            intent.addCategory(Intent.CATEGORY_LAUNCHER);

            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |

                    Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

            ComponentName cn = new ComponentName(packageName1, className);

            intent.setComponent(cn);

            context.startActivity(intent);

        }

    } catch (Exception e) {

        e.printStackTrace();

        Toast.makeText(context.getApplicationContext(), "啟動失敗",

                Toast.LENGTH_LONG).show();

    }
}

而installer的打開在com.android.packageinstaller.installappprogress

public static void startAppByInstallApp(Context context, String packageName) {

    try {
        Intent intent= context.getPackageManager().getLaunchIntentForPackage(
                packageName);
        context.startActivity(intent);
    } catch (Exception e) {

    }
}

而getLaunchIntentForPackage的實際代碼在ApplicationPackageManager

   @Override
    public Intent getLaunchIntentForPackage(String packageName) {
        // First see if the package has an INFO activity; the existence of
        // such an activity is implied to be the desired front-door for the
        // overall package (such as if it has multiple launcher entries).
        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
        intentToResolve.addCategory(Intent.CATEGORY_INFO);
        intentToResolve.setPackage(packageName);
        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
        // Otherwise, try to find a main launcher activity.
        if (ris == null || ris.size() <= 0) {
            // reuse the intent instance
            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
            intentToResolve.setPackage(packageName);
            ris = queryIntentActivities(intentToResolve, 0);
        }
        if (ris == null || ris.size() <= 0) {
            return null;
        }
        Intent intent = new Intent(intentToResolve);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName(ris.get(0).activityInfo.packageName,
                ris.get(0).activityInfo.name);
        return intent;
    }

測試了一下轩猩,最后發(fā)現(xiàn)兩者的不同在于installappprogress多了一個intent.setPackage(packageName)。
那為什么多了一個intent.setPackage(packageName)會再此打開時導致多了Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT


FLAG_ACTIVITY_BROUGHT_TO_FRONT是如何產(chǎn)生的

這是在 com.android.server.am.ActivityStackSupervisor

  final ActivityStack lastStack = getLastStack();
                    ActivityRecord curTop = lastStack == null?
                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);
                    if (curTop != null && (curTop.task != intentActivity.task ||
                            curTop.task != lastStack.topTask())) {
                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
                                sourceStack.topActivity().task == sourceRecord.task)) {
                            // We really do want to push this one into the
                            // user's face, right now.
                            movedHome = true;
                            if ((launchFlags &
                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                // Caller wants to appear on home activity.
                                intentActivity.task.mOnTopOfHome = true;
                            }
                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
                            options = null;
                        }
                    }

關鍵在于 curTop.task != lastStack.topTask()
這個地方我估摸著是因為packageName會影響到task


FLAG_ACTIVITY_BROUGHT_TO_FRONT是如何起作用

這個我還沒找到實際代碼,只能看一下官方解釋

If, when starting the activity, there is already a task running that starts with this activity, then instead of starting a new instance the current task is brought to the front. The existing instance will receive a call to Activity.onNewIntent() with the new Intent that is being started, and with the Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT flag set. This is a superset of the singleTop mode, where if there is already an instance of the activity being started at the top of the stack, it will receive the Intent as described there (without the FLAG_ACTIVITY_BROUGHT_TO_FRONT flag set). See the Tasks and Back Stack document for more details about tasks.

這個FLAG其實是這個意思,比方說用A打開B界轩,此時在A的Intent中加上這個FLAG画饥,再在B中再啟動C,D浊猾,如果這個時候在D中再啟動B抖甘,這個時候最后的棧的情況是 A,C,D,B.

這篇文章有兩個地方?jīng)]解釋到,希望大家補充

  1. 為什么packageName為影響到curTop.task != lastStack.topTask()
  2. FLAG_ACTIVITY_BROUGHT_TO_FRONT是如何起作用的
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葫慎,一起剝皮案震驚了整個濱河市衔彻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偷办,老刑警劉巖艰额,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異椒涯,居然都是意外死亡柄沮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門废岂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祖搓,“玉大人,你說我怎么就攤上這事湖苞≌罚” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵财骨,是天一觀的道長镐作。 經(jīng)常有香客問我,道長隆箩,這世上最難降的妖魔是什么该贾? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮捌臊,結果婚禮上杨蛋,老公的妹妹穿的比我還像新娘。我一直安慰自己娃属,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布护姆。 她就那樣靜靜地躺著矾端,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卵皂。 梳的紋絲不亂的頭發(fā)上秩铆,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音,去河邊找鬼殴玛。 笑死捅膘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的滚粟。 我是一名探鬼主播寻仗,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凡壤!你這毒婦竟也來了署尤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亚侠,失蹤者是張志新(化名)和其女友劉穎曹体,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硝烂,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡箕别,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了滞谢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片串稀。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖爹凹,靈堂內(nèi)的尸體忽然破棺而出厨诸,到底是詐尸還是另有隱情,我是刑警寧澤禾酱,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布微酬,位于F島的核電站,受9級特大地震影響颤陶,放射性物質(zhì)發(fā)生泄漏颗管。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一滓走、第九天 我趴在偏房一處隱蔽的房頂上張望垦江。 院中可真熱鬧,春花似錦搅方、人聲如沸比吭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衩藤。三九已至,卻和暖如春涛漂,著一層夾襖步出監(jiān)牢的瞬間赏表,已是汗流浹背检诗。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瓢剿,地道東北人逢慌。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像间狂,于是被迫代替她去往敵國和親攻泼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容