浅谈Android多屏幕的事

本文深入探讨了Android从4.4 KitKat到N版本的多任务分屏功能实现,解析了am命令在分屏操作中的作用,包括创建、移动任务和调整大小等,并介绍了在Android N中开发者需要注意的事项,如多窗口配置、生命周期、拖放功能等。
摘要由CSDN通过智能技术生成

浅谈Android多屏幕的事


一部手机可以同时看片、聊天,还可以腾出一支手来撸!这么吊的功能(非N版本,非第三方也能实现,你不知道吧)摆在你面前,你不享用?不关注它是怎样实现的?你来,我就满足你的欲望!
一部手机可以同时看片、聊天,还可以腾出一支手来撸==!就像这样:
这里写图片描述

是时候告别来回切换应用屏幕的酸爽了,还可以在分屏模式下两Activity间直接拖放数据!
好高大上的样子!这是怎么实现的?别急,我们一一道来:

kitkat(4.4)版本对多任务分屏的实现

由于相关的代码和功能被封装及隐藏起来,所以我们从dumpsys activity命令作手。
来,直接上一条命令:

am stack boxes

NetEasedeMac-Pro-8:~ netease$ adb shell am stack boxes
Box id=0 weight=0.0 vertical=false bounds=[0,75][1080,1776]
Stack=
  Stack id=0 bounds=[0,75][1080,1776]
    taskId=1: com.android.launcher/com.android.launcher2.Launcher
    taskId=4: com.android.systemui/com.android.systemui.recent.RecentsActivity

Box id=1 weight=0.0 vertical=false bounds=[0,75][1080,1776]
Stack=
  Stack id=1 bounds=[0,75][1080,1776]
    taskId=2: com.android.contacts/com.android.contacts.activities.PeopleActivity
    taskId=3: com.android.email/com.android.email.activity.Welcome

以上命令大致可以看出一些简单明显的东西,最高级为两个Box,每个Box有一个Stack,每个Stack下有n个taskId等等。既然提到am,那我们就去看一看Android源码Am这个类:com.android.commands.am.Am。在里面可以看到一堆的am命令,这些命令的执行在onRun()函数里,我们先看runStack()->runStackBoxes(),一直跟踪下去,会涉及到ActivityManagerService.getStackBoxes()->WindowManagerService.getStackBoxInfos()->DisplayContent.getStackBoxInfos()直接遍历DisplayContent里的mStackBoxes。

用简单的类图来表示其数据结构关系:

StackBox相关简单类图:
这里写图片描述
TaskStack相关的简单类图:
这里写图片描述

有这里Task的概念是什么?
官方定义:“A task (from the activity that started it to the next task activity)defines an atomic group of activities that the user can move to.”。
简单来讲:Task是为了完成一个功能的一系列相关的有序Activity集合,可以理解为用户与App之间对于特定功能的一次会话。一个Task中的Activity可以来自不同的App,比如在邮件App中需要看图片附件,然后会开imageview的Activity来显示它。

以上只是在WMS里分析了StackBox、TaskStack相关的简单数据结构,我们知道对于一个完整的窗口流程还主要涉及到AMS、SF联合管理及渲染显示。那么在AMS里是怎样进行管理的呢?不急,我们看第二个灵魂级的am命令

灵魂级的am命令:am stack create

am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>
注解如下:

am stack create: create a new stack relative to an existing one.
  <TASK_ID>: the task to populate the new stack with. Must exist.
  <RELATIVE_STACK_BOX_ID>: existing stack box's id.
  <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>
              1: after <RELATIVE_STACK_BOX_ID>
              2: to left of <RELATIVE_STACK_BOX_ID>
              3: to right of <RELATIVE_STACK_BOX_ID>
              4: above <RELATIVE_STACK_BOX_ID>
              5: below <RELATIVE_STACK_BOX_ID>
 <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" +

试一下:

NetEasedeMac-Pro-8:~ netease$ adb shell am stack create 3 1 4 0.7
createStack returned new stackId=2

直接上效果图:

这里写图片描述

这里申明一下:由于我的模拟器有问题,上图是借用http://androidinternalsblog.blogspot.com/2014/03/split-screens-in-android-exist.html 里的,不过效果一样的。
这就是android分屏的鼻祖,这时候的stack boxes输出如下:

NetEasedeMac-Pro-8:~ netease$ adb shell am stack boxes
Box id=1 weight=0.5 vertical=true bounds=[0,75][1080,1776]
First child=
  Box id=2 weight=0.0 vertical=false bounds=[0,75][1080,925]
  Stack=
    Stack id=2 bounds=[0,75][1080,925]
      taskId=3: com.android.email/com.android.email.activity.Welcome
Second child=
  Box id=3 weight=0.0 vertical=false bounds=[0,925][1080,1776]
  Stack=
    Stack id=1 bounds=[0,925][1080,1776]
      taskId=2: com.android.contacts/com.android.contacts.activities.PeopleActivity

Box id=0 weight=0.0 vertical=false bounds=[0,75][1080,1776]
Stack=
  Stack id=0 bounds=[0,75][1080,1776]
    taskId=1: com.android.launcher/com.android.launcher2.Launcher

可以看到之前的Box_id1一分为二:Box_id2和Box_id3(充分说明StackBox的数据结构为树),另外stack_id3从原Box_id1(也可以理解成现在的Box_id2)的移到了Box_id3。

看看am stack create是怎么实现的吧,回到Am里的runStackCreate()->AMS.createStack()

  public int createStack(int taskId, int relativeStackBoxId, int position, float weight) {
        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                "createStack()");
        if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" +
                relativeStackBoxId + " position=" + position + " weight=" + weight);
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
            try {
                int stackId = mStackSupervisor.createStack();
                mWindowManager.createStack(stackId, relativeStackBoxId, position, weight);
                if (taskId > 0) {
                    moveTaskToStack(taskId, stackId, true);
                }
                return stackId;
   
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值