TaskView简述

TaskView简述

TaskView是什么

首先看一下官方的注释(基于Android12.0.0_r3版本的代码分析):

View that can display a task
是一个可以展示Task的视图。那有什么用呢?简单来说就是跨进程来展示UI。就比如我有两个进程,进程A和进程B。我想在进程A中启动进程B的Activity,这时候就可以使用TaskView来实现这个功能。

接着再来说TaskView是什么?

TaskView 是SurfaceView的子类,并且实现了
SurfaceHolder.Callback, ShellTaskOrganizer.TaskListener, ViewTreeObserver.OnComputeInternalInsetsListener这三个接口

首先说一下SurfaceView,这个用过的人都有些印象,比如摄像头的录制展示可以用SurfaceView来展示或者是一些需要即时更新的UI可以通过SurfaceView来进行展示。换大多数人的说法就是挖了个洞,也确实是,如果要是保证效率,没必要做那么多没用的操作,有个捷径何尝不是个好事情~。
接着是 SurfaceHolder.Callback,注册了这个Callback,就能够接受到Surface改变的回调,经典的三个方法surfaceCreated,surfaceChangedsurfaceDestroyed,一般是和SurfaceView配合使用的。
说到这,可以把TaskView理解为一个SurfaceView。
接着说一下 ShellTaskOrganizer.TaskListener这个接口,这个就属于是WindowManager/Shell这一套的相关接口了。在系统的任务更改的时候,就能在这个监听中收到回调。在这里,TaskView是这个接口的实现类,那就说明,ShellTaskOrganizer对TaskView进行管理,当有消息来时,就会去通知给TaskView。
最后说一下ViewTreeObserver.OnComputeInternalInsetsListener这个接口,这个接口在源码中搜索了下,发现了一个熟悉的类VoiceInteractionSession,接触到的项目对于语音助手的使用就是基于这个类的相关交互的,往下翻,发现熟悉的onShowonHide方法等等。。。有点跑题了。布局完成的时候,如果实现了这个接口,就能够onComputeInternalInsets接受到回调,语音助手收到后回去进行自己的UI绘制。

TaskView的创建

创建还不好说么,直接new一个,开句玩笑。具体如何创建,还得看谷歌源生代码是怎么使用的。

/** Interface to create TaskView. */
@ExternalThread
public interface TaskViewFactory {
    /** Creates an {@link TaskView} */
    void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate);
}

搜索TaskView的构造方法,发现TaskViewFactory,听名字就是一个TaskView的创建类,查看注释,更加确定就是通过这个接口来创建TaskView了。终归是一个接口,去看下具体实现。

/** Factory controller which can create {@link TaskView} */
public class TaskViewFactoryController {
    private final ShellTaskOrganizer mTaskOrganizer;
    private final ShellExecutor mShellExecutor;
    private final TaskViewFactory mImpl = new TaskViewFactoryImpl();

    public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer,
            ShellExecutor shellExecutor) {
        mTaskOrganizer = taskOrganizer;
        mShellExecutor = shellExecutor;
    }

    public TaskViewFactory asTaskViewFactory() {
        return mImpl;
    }

    /** Creates an {@link TaskView} */
    public void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate) {
        TaskView taskView = new TaskView(context, mTaskOrganizer);
        executor.execute(() -> {
            onCreate.accept(taskView);
        });
    }

    private class TaskViewFactoryImpl implements TaskViewFactory {
        @ExternalThread
        public void create(@UiContext Context context,
                Executor executor, Consumer<TaskView> onCreate) {
            mShellExecutor.execute(() -> {
                TaskViewFactoryController.this.create(context, executor, onCreate);
            });
        }
    }
}

可以看到TaskViewFactoryController的内部类TaskViewFactoryImpl实现了TaskViewFactory这个接口,并且交给TaskViewFactoryController来进行TaskView的创建。到这里大概就知道了,创建TaskView时需要创建一个ShellTaskOrganizer和一个ShellExecutor对象,接着再来创建一个TaskView对象。这里留个猜测,等到TaskView启动的Activity的onCreate()执行后,才去创建TaskView对象。

再来看一下TaskView的构造函数干了些什么事情。

public TaskView(Context context, ShellTaskOrganizer organizer) {
    super(context, null, 0, 0, true /* disableBackgroundLayer */);
    mTaskOrganizer = organizer;
    mShellExecutor = organizer.getExecutor();
    setUseAlpha();
    getHolder().addCallback(this);
    // 用来打印警告的log,以及告诉关闭的方法名。要成对使用
    mGuard.open("release");
}

首先mTaskOrganizermShellExecutor在上面可以看到,都是在构造的时候需要的参数,接着setUseAlpha()方法是用来设置透明度的。下面getHolder().addCallback(this)是向其父类SurfaceView注册SurfaceHolder.Callback监听的。
到此为止,TaskView的创建暂时来个中场休息~


TaskView的使用

对于TaskView的使用,去启动界面使用startActivity方法即可,向其传递一个PendingIntent对象,就能够让其在TaskView中去启动一个其他的Activity。但是这里先说一下另一个比较重要的点,startActivity随后再说。这里说一下要进行注册的监听,也就是TaskView.Listener,该监听是需要TaskView的setListener方法去进行注册的。

TaskView.Listener

为什么要先说这个的?首先把状态的监听注册好,能够很好的去监听我们通过TaskView展示其他进程的Activity的状态,至少能够知道执行到了TaskView的哪一步,如果出现问题方便我们去很快的定位。
先看看这个监听都包含了哪些方法:

/** Callback for listening task state. */
public interface Listener {
    /** Called when the container is ready for launching activities. */
    default void onInitialized() {}

    /** Called when the container can no longer launch activities. */
    default void onReleased() {}

    /** Called when a task is created inside the container. */
    default void onTaskCreated(int taskId, ComponentName name) {}

    /** Called when a task visibility changes. */
    default void onTaskVisibilityChanged(int taskId, boolean visible) {}

    /** Called when a task is about to be removed from the stack inside the container. */
    default void onTaskRemovalStarted(int taskId) {}

    /** Called when a task is created inside the container. */
    default void onBackPressedOnTaskRoot(int taskId) {}
}

看一下官方的注释,这个监听就是用来监听Task的状态的。

onInitialized这个方法说明当前的容器已经准备好去启动Activity了,当TaskView收到了surfaceCreated【SurfaceHolder.Callback】的回调之后,便会去给注册的监听发送onInitialized的消息。
onTaskCreated这个方法在Task已经被创建并且放入容器时,回去收到这个回调,当TaskView收到onTaskAppeared【ShellTaskOrganizer.TaskListener】的回调后,会去告知Listener的onTaskCreated
onTaskVisibilityChanged这个方法在调用updateTaskVisibility()的方法时回去通知监听的可见性变化,也即surfaceCreated,surfaceDestroyedonTaskAppeared时会去更新可见性变化。
onReleased这个方法在容器不在启动Activity的时候进行调用,一般我们在使用完后可以手动去release()
onTaskRemovalStarted这个方法在Task在栈中即将移除时调用,即在onTaskVanished【ShellTaskOrganizer.TaskListener】回调后去执行。
onBackPressedOnTaskRoot当Task被创建并且放入容器时进行调用,即在onBackPressedOnTaskRoot【ShellTaskOrganizer.TaskListener】回调后去执行。

上面提到的 【ShellTaskOrganizer.TaskListener】 都是在ShellTaskOrganizer这个类分发下来的,之后也会再继续整理整体的流程。而实现SurfaceHolder.Callback的三个方法,是在其父类另一个父类SurfaceView进行可见性调整的时候,会向其下发对应的回调。

startActivity

TaskView归根到底,还是去起一个Activity,只不过展示的位置变了。先看下源码:

/**
    * Launch a new activity.
    *
    * @param pendingIntent Intent used to launch an activity.
    * @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()}
    * @param options options for the activity.
    * @param launchBounds the bounds (window size and position) that the activity should be
    *                     launched in, in pixels and in screen coordinates.
    */
public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
        @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
    prepareActivityOptions(options, launchBounds);
    try {
        pendingIntent.send(mContext, 0 /* code */, fillInIntent,
                null /* onFinished */, null /* handler */, null /* requiredPermission */,
                options.toBundle());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

需要传入四个参数,分别是一个PendingIntent,Intent,ActivityOptions和Rect。第一个参数是即将启动的Activity的Intent信息,第二个参数是Intent的补充信息,第三个参数是Activity的一些参数,最后一个参数是展示的大小以及位置。
prepareActivityOptions会将Rect数据存储到ActivityOptions当中去并且向ShellTaskOrganizer注册自身【ShellTaskOrganizer.TaskListener】。

TaskView.Listener # onTaskCreated()

这里先简单记录一下和onTaskCreated()方法的相关流程。
所谓的TaskView,现在终于算是到了Task了,到我现在分析的这个位置,Task类持有一个ActivityTaskManagerService对象,ActivityTaskManagerService又会持有一个 TaskOrganizerController对象,随后去进行跨进程通信。这里的数理逻辑是倒着来进行分析的。

TaskView.Listener ShellTaskOrganizer.TaskListener TaskOrganizer ITaskOrganizer TaskOrganizerController.TaskOrganizerCallbacks TaskOrganizerController.TaskOrganizerState TaskOrganizerController Task Task通过其持有的ActivityTaskMangerService对象,再用其对象持有的TaskOrganizerController进行分发 sendTaskAppeared onTaskAppeared onTaskAppeared onTaskAppeared 进行跨进程通信 onTaskAppeared onTaskAppeared onTaskCreated TaskView.Listener ShellTaskOrganizer.TaskListener TaskOrganizer ITaskOrganizer TaskOrganizerController.TaskOrganizerCallbacks TaskOrganizerController.TaskOrganizerState TaskOrganizerController Task

在这个流程图中,以TaskOrganizerController作为一个参考线,在这个流程图的左侧,全都是属于客户端的范畴,而右侧是服务端的范畴,服务端跨进程向客户端进行数据的发送,我们在收到对应的回调后再进行相关的处理。
而正如其名,TaskOrganizerController就是用来进行Task分发的控制的。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值