android 记一次打开应用后的通病

3,212 阅读2分钟

现象描述

app 在应用市场下载完成后,点击打开,按照 app 的一般流程首先会启动 Splash 界面,再进入首页。此时你按下 home 键,再从桌面点击应用图标,你会发现应用又走到了 Splash 界面再进入首页。再次按 home 键重复刚才的动作现象依旧,通过将应用结束或杀掉进程应用就会恢复正常。当然这种现象理论上来说在你安装完应用后只会出现一次,但终归还是会影响用户体验。(如果用户进入了比较深层次的页面,这个体验对用户来说绝对是个灾难)

大家可以去随便下一款 app 试一下,大概率会有这种现象,比如下面的 app。

liuli

大厂 app 就不要试了,别人早就处理好了这个问题。所以先看一下网易和 b站是怎么解决这个问题的。

解决方案

我们先来看网易的解决办法:

    paramJoinPoint = paramAdActivity.getIntent();
    int k = 0;
    int i;
    if ((paramJoinPoint != null) && (paramAdActivity.getIntent().getBooleanExtra("out", false))) {
      i = 1;
    } else {
      i = 0;
    }
    long l = System.currentTimeMillis();
    paramAdActivity.setTheme(2131689487);
    int j = k;
    if (!paramAdActivity.isTaskRoot()) // 关键代码1
    {
      j = k;
      if (paramAdActivity.getIntent() != null)
      {
        j = k;
        if ((paramAdActivity.getIntent().getFlags() & 0x400000) != 0) { // 关键代码 2
          j = 1;
        }
      }
    }
    if (j == 0) {
      fp.a(paramAdActivity.getIntent(), AdFragment.class.getName(), "AdFragment", null);
    }
    paramAdActivity.onCreate(paramBundle);
    if (j != 0)
    {
      paramAdActivity.finish();
      return;
    }

核心逻辑如下

if(!isTaskRoot) {
	if((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
		finish();
		return;
	}
}
    /**
     * This flag is not normally set by application code, but set for you by
     * the system as described in the
     * {@link android.R.styleable#AndroidManifestActivity_launchMode
     * launchMode} documentation for the singleTask mode.
     */
    public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 0x00400000;

接着是 B 站的:

  Object localObject;
    if ((m.a.a((Context)this)) && (!isTaskRoot()))
    {
      localObject = getIntent();
      Intrinsics.checkExpressionValueIsNotNull(localObject, "intent");
      localObject = ((Intent)localObject).getAction();
      if ((getIntent().hasCategory("android.intent.category.LAUNCHER")) && (TextUtils.equals((CharSequence)localObject, (CharSequence)"android.intent.action.MAIN")))
      {
        m.a.b((Context)this);
        b(); // 调用 finish()
        return;
      }
    }


核心逻辑如下:

if(!isTaskRoot()) {
  if ((getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)) && (TextUtils.equals(getIntent().getAction(), Intent.ACTION_MAIN)) {
    finish();
    return
  }
}

总结

两种方案的逻辑判断都很简单,且前置条件都是先判断 isTaskRoot,差异在于后续的判断处理,就我个人而言觉得 b 站的方案更易于理解。