【TaskStackListener】Android 中用于监听和响应任务栈

【TaskStackListener】Android 中用于监听和响应任务栈

  • [一、TaskStackListener 的主要功能和应用场景](#一、TaskStackListener 的主要功能和应用场景)
  • [二、TaskStackListener 的核心方法](#二、TaskStackListener 的核心方法)
  • [三、如何使用 TaskStackListener (仅限系统应用)](#三、如何使用 TaskStackListener (仅限系统应用))
  • 四、总结

TaskStackListener 是一个隐藏的 Android API,它为系统级应用提供了一套强大的机制,用于监听和响应任务栈 (Task Stack) 的变化。通俗地说,它就像一个安装在 Android 系统任务管理器中的"侦听器",能够实时感知应用的启动、切换、关闭等行为,并触发相应的回调。

然而,需要特别注意的是,TaskStackListener 是一个非公开的 API (Hidden API),这意味着 Google 并不保证其在不同 Android 版本间的稳定性和可用性,且不建议第三方应用程序直接使用。对于普通应用开发者而言,强行使用可能会导致应用在未来的系统更新中出现兼容性问题。

一、TaskStackListener 的主要功能和应用场景

对于有系统开发权限的开发者而言,TaskStackListener 在以下场景中非常有用:

  • 系统级界面定制: 例如,在车载系统或定制化的 Launcher 中,需要根据当前前台应用的变化来调整界面元素或执行特定逻辑。
  • 应用行为监控: 在一些特殊的系统工具中,可以用来监控特定应用的启动和关闭事件。(我看过的Launcher和SystemUI有类似的功能)
  • 多窗口和分屏管理: 在实现复杂的多窗口功能时,需要精确地感知任务栈的变动。

二、TaskStackListener 的核心方法

TaskStackListener 是一个抽象类,开发者需要继承它并重写其内部的方法来处理不同的任务栈变化事件。以下是一些关键的回调方法:

  • onTaskStackChanged(): 这是一个最通用和最频繁被触发的回调。每当任务栈发生任何变化,例如 Activity 的启动、销毁,任务的创建、移除或顺序改变,都会调用此方法。
  • onTaskCreated(int taskId, ComponentName componentName): 当一个新的任务被创建时调用。这通常发生在用户启动一个新应用或一个应用以新的任务栈方式启动一个 Activity 时。
  • onTaskRemoved(int taskId): 当一个任务被移除时调用。例如,用户从最近任务列表中划掉一个应用。
  • onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo): 当一个已存在的任务被切换到前台时调用。例如,用户通过最近任务列表切换回一个后台应用。
  • onActivityPinned(String packageName, int userId, int taskId, int displayId): 当一个 Activity 进入画中画 (Pinned) 模式时调用。
  • onActivityUnpinned(): 当一个 Activity 退出画中画模式时调用。
java 复制代码
/**
 * Classes interested in observing only a subset of changes using ITaskStackListener can extend
 * this class to avoid having to implement all the methods.
 *
 * @hide
 */
public abstract class TaskStackListener extends ITaskStackListener.Stub {

    /** Whether this listener and the callback dispatcher are in different processes. */
    private boolean mIsRemote = true;

    @UnsupportedAppUsage
    public TaskStackListener() {
    }

    /** Indicates that this listener lives in system server. */
    public void setIsLocal() {
        mIsRemote = false;
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskStackChanged() throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityPinned(String packageName, int userId, int taskId, int rootTaskId)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityUnpinned() throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
            boolean clearedTask, boolean wasVisible) throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityForcedResizable(String packageName, int taskId, int reason)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityDismissingDockedTask() throws RemoteException {
    }

    @Override
    public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
            int requestedDisplayId) throws RemoteException {
        onActivityLaunchOnSecondaryDisplayFailed();
    }

    /**
     * @deprecated see {@link
     *         #onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo, int)}
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
            int requestedDisplayId) throws RemoteException {
    }

    @Override
    public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskRemoved(int taskId) throws RemoteException {
    }

    @Override
    public void onTaskMovedToFront(RunningTaskInfo taskInfo)
            throws RemoteException {
        onTaskMovedToFront(taskInfo.taskId);
    }

    /**
     * @deprecated see {@link #onTaskMovedToFront(RunningTaskInfo)}
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskMovedToFront(int taskId) throws RemoteException {
    }

    @Override
    public void onTaskRemovalStarted(RunningTaskInfo taskInfo)
            throws RemoteException {
        onTaskRemovalStarted(taskInfo.taskId);
    }

    /**
     * @deprecated see {@link #onTaskRemovalStarted(RunningTaskInfo)}
     */
    @Deprecated
    public void onTaskRemovalStarted(int taskId) throws RemoteException {
    }

    @Override
    public void onTaskDescriptionChanged(RunningTaskInfo taskInfo)
            throws RemoteException {
        onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription);
    }

    /**
     * @deprecated see {@link #onTaskDescriptionChanged(RunningTaskInfo)}
     */
    @Deprecated
    public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
            throws RemoteException {
    }

    @Override
    public void onTaskProfileLocked(RunningTaskInfo taskInfo, int userId)
            throws RemoteException {
        onTaskProfileLocked(taskInfo);
    }

    /**
     * @deprecated see {@link #onTaskProfileLocked(RunningTaskInfo, int)}
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskProfileLocked(RunningTaskInfo taskInfo)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
        if (mIsRemote && snapshot != null && snapshot.getHardwareBuffer() != null) {
            // Preemptively clear any reference to the buffer
            snapshot.getHardwareBuffer().close();
        }
    }

    @Override
    public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)
            throws RemoteException {
    }

    @Override
    public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
    }

    @Override
    public void onRecentTaskListUpdated() throws RemoteException {
    }

    @Override
    public void onRecentTaskListFrozenChanged(boolean frozen) {
    }

    @Override
    public void onTaskFocusChanged(int taskId, boolean focused) {
    }

    @Override
    public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
    }

    @Override
    public void onActivityRotation(int displayId) {
    }

    @Override
    public void onTaskMovedToBack(RunningTaskInfo taskInfo) {
    }

    @Override
    public void onLockTaskModeChanged(int mode) {
    }
}

三、如何使用 TaskStackListener (仅限系统应用)

对于拥有系统权限的应用,使用 TaskStackListener 的基本步骤如下:

  1. 定义一个继承自 TaskStackListener 的类:

    java 复制代码
    import android.app.TaskStackListener;
    import android.content.ComponentName;
    import android.os.RemoteException;
    import android.util.Log;
    
    public class MyTaskStackListener extends TaskStackListener {
        private static final String TAG = "MyTaskStackListener";
    
        @Override
        public void onTaskStackChanged() throws RemoteException {
            Log.d(TAG, "onTaskStackChanged");
            // 任务栈发生变化
        }
    
        @Override
        public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
            Log.d(TAG, "onTaskCreated: taskId=" + taskId + ", componentName=" + componentName);
            // 新任务创建
        }
    
        @Override
        public void onTaskRemoved(int taskId) throws RemoteException {
            Log.d(TAG, "onTaskRemoved: taskId=" + taskId);
            // 任务被移除
        }
    
        @Override
        public void onTaskMovedToFront(int taskId) throws RemoteException {
             Log.d(TAG, "onTaskMovedToFront: taskId=" + taskId);
             // 任务被切换到前台
        }
    }
  2. 在系统服务中注册监听器:

    通常,这需要在具有系统权限的服务(例如系统UI或自定义的系统服务)中完成。

    java 复制代码
    import android.app.ActivityManager;
    import android.content.Context;
    
    public class MySystemMonitoringService extends Service {
        private MyTaskStackListener mTaskStackListener;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mTaskStackListener = new MyTaskStackListener();
            try {
                ActivityManager.getService().registerTaskStackListener(mTaskStackListener);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if (mTaskStackListener != null) {
                try {
                    ActivityManager.getService().unregisterTaskStackListener(mTaskStackListener);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        // ... 其他服务相关的代码
    }

关于注册监听还可以通过 ActivityTaskManager,Android 框架进行了重构,将窗口管理和活动生命周期相关的核心逻辑分离到了专门的 ActivityTaskManager 中,而 ActivityManager 则更多地保留了应用层面的信息管理功能。

java 复制代码
IBinder binder = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
IActivityTaskManager atmService = IActivityTaskManager.Stub.asInterface(binder);
atmService .registerTaskStackListener(mTaskStackListener);

四、总结

TaskStackListener 是一个强大的工具,但它的使用范围被严格限制在系统应用层面。对于广大的第三方应用开发者而言,了解其存在和功能有助于更深入地理解 Android 的任务管理机制,但在实际开发中应避免直接使用。

需要特别指出的是,从 Android 12 开始,Google 对任务和窗口管理进行了重构。TaskStackListener 的部分功能和概念已经被新的 API TaskOrganizer 所取代。

TaskOrganizer 是一个更为强大和灵活的接口,它允许应用(同样需要特定权限)直接组织和控制任务的显示,例如在自定义的 Launcher 中实现对应用窗口的管理。对于希望在较新 Android 版本上实现类似功能开发者来说,应该研究和使用 TaskOrganizer。

相关推荐
前端小D20 小时前
React Native Android 项目搭建
android·react native·react.js
恋猫de小郭21 小时前
感人,Flutter 居然有了一个超实用提案,期待落地
android·前端·flutter
CS_Zero1 天前
安卓开发:Linux的android工具命令
android·linux·运维
fellow991 天前
DSH Desktop - Android Edition
android·agent·deepseek·harness·dsh
Carson带你学Android1 天前
Android Studio Rabbit 2 发布:除了Gemini,40+ AI Agent 正式入驻!
android·ai编程
三少爷的鞋1 天前
Java 线程自上而下,Kotlin 协程自下而上
android
好的佩奇2 天前
Dart 之增强枚举
android·flutter·dart
梦影_2 天前
MySQL进阶教程(五)—— SQL调优(下)
android·大数据·数据库·后端·sql·mysql·database
好的佩奇2 天前
蓝牙之无线电与通信距离
android·flutter·蓝牙
vilya2 天前
我把一套完整的 Python Agent 运行时塞进手机 APK:依赖闭包、Rust 轮子和三个真机坑
android