退出Compass时闪现其他界面问题分析

一、问题现象
首先进入非launcher任意界面,按Home键返回,点击Compass,弹出Compass请求device’s location权限,勾选Never ask again,点击DENY后进入应用,点击底部小字,等待从下方弹出一个获取权限的activity后按back键退出Compass,退出过程中会闪现之前打开的界面。

Platform: MSM8976
Android version: Android M 6.0.1
系统软件版本: SWA2I

二、初步分析结论
Activity被finish的时候,如果当前Activity不是所在Task中最后的一个,那么系统会重新设定Task中ActivityRecord的frontOfTask值,而frontOfTask的值会对FocusedActivity产生影响,导致上面所出现的问题。
三、具体分析过程
正常情况下,打开Compass后会先启动开始界面Compass.java,同时弹出权限申请框,随后会从启动界面Compass.java跳转到Compass的主界面CompassMainActivity.java,
(1)在启动每个Activity的时候,都会在startActivityLocked(ActivityStack.java)方法中调用setFrontOfTask(TaskRecord.java)方法,对task中ActivityRecord的frontOfTask值进行设置,跳转到主界面CompassMainActivity.java后,此时Task中有以上两个ActivityRecord,根据setFrontOfTask方法的逻辑,ActivityRecord{e188681 u0 com.jrdcom.compass/.Compass t20}的frontOfTask属性被设置为true,随后启动界面Compass.java会被finish,在finish的过程中又会在finishActivityLocked方法中判断正在finish的Activity在task中的位置,如果(index < (activities.size() - 1)),那么就会再一次调用setFrontOfTask,此时Compass.index=0,(activities.size()-1)=1, ActivityRecord{eaedfb0 u0 com.jrdcom.compass/.CompassMainActivity t20}的FrontOfTask会被设置为true。

    /**
     * @return Returns true if the activity is being finished, false if for
     * some reason it is being left as-is.
     */
    final boolean requestFinishActivityLocked(IBinder token, int resultCode,
            Intent resultData, String reason, boolean oomAdj) {
        ActivityRecord r = isInStackLocked(token);
        if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(TAG_STATES,
                "Finishing activity token=" + token + " r="
                + ", result=" + resultCode + ", data=" + resultData
                + ", reason=" + reason);
        if (r == null) {
            return false;
        }
        finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
        return true;
    }

    /**
     * @return Returns true if this activity has been removed from the history
     * list, or false if it is still in the list and will be removed later.
     */
    final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
            String reason, boolean oomAdj) {
        if (r.finishing) {
            Slog.w(TAG, "Duplicate finish request for " + r);
            return false;
        }

        r.makeFinishingLocked();
        final TaskRecord task = r.task;
        EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                r.userId, System.identityHashCode(r),
                task.taskId, r.shortComponentName, reason);
        final ArrayList<ActivityRecord> activities = task.mActivities;
        final int index = activities.indexOf(r);
        if (index < (activities.size() - 1)) {
            task.setFrontOfTask();
            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
                // If the caller asked that this activity (and all above it)
                // be cleared when the task is reset, don't lose that information,
                // but propagate it up to the next activity.
                ActivityRecord next = activities.get(index+1);
                next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
            }
        }
        r.pauseKeyDispatchingLocked();

        adjustFocusedActivityLocked(r, "finishActivity");

    /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
    final void setFrontOfTask() {
        boolean foundFront = false;
        final int numActivities = mActivities.size();
        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
            final ActivityRecord r = mActivities.get(activityNdx);
            if (foundFront || r.finishing) {
                r.frontOfTask = false;
            } else {
                r.frontOfTask = true;
                // Set frontOfTask false for every following activity.
                foundFront = true;
            }
        }
        if (!foundFront && numActivities > 0) {
            // All activities of this task are finishing. As we ought to have a frontOfTask
            // activity, make the bottom activity front.
            mActivities.get(0).frontOfTask = true;
        }
    }

(2)紧接着按back键退出Compass,被finish的是主界面CompassMainActivity,同样调用 finishActivityLocked,
1. 若此时启动界面已经被finish,启动界面activity也已经从历史列表中移除,CMA.index=0,(activities.size()-1)=0,task中只有一个ActivityRecord,不再重新设置frontOfTask的值;
2. 若此时启动界面activity还没有从历史列表中移除,CMA.index=1, (activities.size()-1)=1, 同样 index<(activities.size()-1)不成立,也不再重新设置frontOfTask的值。
紧接着调用 adjustFocusedActivityLocked方法对FocusedActivity进行处理。

    private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
        if (mStackSupervisor.isFrontStack(this) && mService.mFocusedActivity == r) {
            System.out.println("ran.zhou-AS-L2663-r = " + r);
            ActivityRecord next = topRunningActivityLocked(null);
            final String myReason = reason + " adjustFocus";
            if (next != r) {
                final TaskRecord task = r.task;
                //modify by minzhang@tcl.com start
                //merge from google,https://code.google.com/p/android/issues/detail?id=192090
                //as same as defect 958818.
                boolean adjust = false;
//                 || (r+"").contains("CompassMainActivity")
                if ((next == null || next.task != task) && r.frontOfTask){
                    if (task.isOverHomeStack() && task == topTask()) {
                        adjust = true;
                    } else {
                        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                            final TaskRecord tr = mTaskHistory.get(taskNdx);
                            //It is importance ! Annotate by minzhang@tcl.com
                            if (tr.getTopActivity() != null) {
                                break;
                            } else if (tr.isOverHomeStack()) {
                                adjust = true;
                                break;
                            }
                        }
                    }
                }
                //modify by minzhang@tcl.com end
                if (adjust) {
                    // For non-fullscreen stack, we want to move the focus to the next visible
                    // stack to prevent the home screen from moving to the top and obscuring
                    // other visible stacks.
                    if (!mFullscreen
                            && adjustFocusToNextVisibleStackLocked(null, myReason)) {
                        return;
                    }
                    // Move the home stack to the top if this stack is fullscreen or there is no
                    // other visible stack.
                    if (mStackSupervisor.moveHomeStackTaskToTop(
                            task.getTaskToReturnTo(), myReason)) {
//moveHomeStackTaskToTop会调用setFocusedActivityLocked.
                        // Activity focus was already adjusted. Nothing else to do...
                        return;
                    }
                }
            }

            final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
            if (top != null) {
                mService.setFocusedActivityLocked(top, myReason);
            }
        }
    }

(3)adjustFocusedActivityLocked方法是调用setFocusedActivityLocked方法对焦点activity进行调整的,此时会把HomeStack移动到顶端,把ActivityRecord{7fafecf u0 com.google.android.googlequicksearchbox/com.google.android.launcher.GEL t18}设置为FocusedActivity。

出现问题的情况下,经过以上步骤(1)过后,立即点击主界面下方小字(此时主界面还没有从history list中移除),弹出申请权限的GrantPermissionsActivity,startActivityLocked()方法会再一次调用setFrontOfTask,此时Compass.finishing=true,结果为CMS.frontOfTask=true。

(4)弹出GrantPermissionsActivity后按back键,依次对GrantPermissionsActivity、CompassMainActivity执行finishActivityLocked方法,此时启动界面activity Compass依然还没有从history中移除,GPA.index = 2, CMA.index = 1, Compass.index = 0, activities.size()=3,在finish CMA的时候调用了setFrontOfTask方法,根据代码逻辑,mActivities.get(0).frontOfTask=true,即Compass.frontOfTask=true, 导致在finish CMA的时候adjustFocusedActivityLocked方法在if ((next == null || next.task != task) && r.frontOfTask){时没有走进去,而是继续往下执行走到了下面代码:

            final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
            if (top != null) {
                mService.setFocusedActivityLocked(top, myReason);
            }

在此处查找处于最顶端的运行中的activity,即开头所提到的任意非launcher activity,并把其设置为FocusedActivity,导致了退出之前闪了一下,接下来继续执行之前的finish步骤,把ActivityRecord{7fafecf u0 com.google.android.googlequicksearchbox/com.google.android.launcher.GEL t18}设置为FocusedActivity,最终返回到launcher界面。
(5)若经过步骤(1)后,经过几秒等待启动界面从history list中移除后再点击主界面下方小字,等待GPA弹出后立即按back键退出,则CMS.index = 0, GAP.index = 1, activities.size() = 2, mActivities.get(0).frontOfTask = true, 即CMS.frontOfTask = true, 代码正常执行,显示正常。
(6)若经过步骤(1)后,经过几秒等待启动界面从history list中移除后再点击主界面下方小字,等待GPA弹出后等待GPA也从history list中移除,则CMS.index = 0,activities.size() = 1, CMS.frontOfTask依然为true,再按back键退出,显示正常。
四、解决方案
此问题应该属于项目代码缺陷,没有针对bug中的测试方法进行处理,在finish Activity的时候从history list中移除过于缓慢,针对Compass这个特定例子,通过修改代码:

“`
if ((next == null || next.task != task) && r.frontOfTask){ ===>修改为
if ((next == null || next.task != task) && (r.frontOfTask || (r+””).contains(“CompassMainActivity”))){

`
强制性引导代码执行到正常代码块,以解决文中问题。

通用性修改的话,个人觉得应该在从history list中移除Activity的逻辑上进行修改,使Activity能够及时从history list中移除,次之则是在finishActivityLocked(ActivityStack.java)中执行setFrontOfTask()方法的判断条件这个地方,或者在setFrontOfTask()方法的逻辑上进行修改。“

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 CentOS 上安装 MongoDB 5 需要以下步骤: 1. 添加 MongoDB 官方的 YUM 源 ``` sudo vi /etc/yum.repos.d/mongodb-org-5.0.repo ``` 在文件中添加以下内容: ``` [mongodb-org-5.0] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/5.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-5.0.asc ``` 2. 安装 MongoDB ``` sudo yum install -y mongodb-org ``` 3. 启动 MongoDB 服务 ``` sudo systemctl start mongod ``` 4. 配置 MongoDB 认证 编辑 MongoDB 配置文件 `/etc/mongod.conf`,找到 `security` 部分,取消注释并设置为 `enabled: true`,保存并退出。 ``` security: authorization: enabled ``` 5. 创建管理员账户 启动 MongoDB 后,使用 `mongo` 命令进入 MongoDB Shell,创建一个管理员账户,如下: ``` use admin db.createUser( { user: "admin", pwd: "password", roles: [ { role: "root", db: "admin" } ] } ) ``` 注意将 `password` 替换成你自己的密码。 6. 重启 MongoDB 服务 ``` sudo systemctl restart mongod ``` 7. 使用 MongoDB Compass 连接 打开 MongoDB Compass,点击 `New Connection`,在 `Connection Settings` 中输入以下信息: - `Hostname`: 服务器的 IP 地址或者域名 - `Port`: MongoDB 服务监听的端口,默认为 27017 - `Authentication`: 选择 `Username/Password`,并输入管理员账户的用户名和密码 - 点击 `Connect` 连接到 MongoDB 服务器。 如果一切正常,你应该能够连接到 MongoDB 服务器并进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值