You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

将AccessibilityEvent传入后台线程后属性值丢失问题咨询

解决AccessibilityEvent传入AsyncTask后属性丢失的问题

这个问题我之前也碰到过,其实是Android系统对AccessibilityEvent的复用优化机制搞的鬼!

原因分析

Android为了提升性能,不会每次都创建新的AccessibilityEvent对象,而是维护了一个对象池。当onAccessibilityEvent()方法执行完毕后,系统会把当前的事件对象回收进池子里,同时清空它的所有属性(比如mEventTime置0、mPackageName设为null),等待下一次事件触发时复用。而你的AsyncTask是在后台线程执行,大概率会比onAccessibilityEvent()方法晚完成,这时候原来的事件对象已经被系统重置了,自然拿不到有效属性。

两种解决方案

1. 复制AccessibilityEvent对象

通过AccessibilityEvent.obtain(event)方法复制一个独立的事件副本,这个副本不会被系统回收,AsyncTask可以安全地使用它的所有属性。注意用完之后一定要调用recycle()释放资源,避免内存泄漏。

修改你的代码如下:

public class MyAccessibilityService extends AccessibilityService { 
    public void onAccessibilityEvent(AccessibilityEvent event) { 
        // 复制事件对象,生成独立副本
        AccessibilityEvent copiedEvent = AccessibilityEvent.obtain(event);
        new MyTestAsync().execute(copiedEvent); 
    } 

    public class MyTestAsync extends AsyncTask<Object, Void, Void> { 
        private AccessibilityEvent event; 

        @Override 
        protected Void doInBackground(Object... params) { 
            this.event = (AccessibilityEvent) params[0]; 
            // 这里可以正常访问event的所有属性了
            
            // 用完后记得回收副本
            event.recycle();
            return null; 
        } 
    } 
}

2. 提前提取所需属性

如果你不需要完整的AccessibilityEvent对象,更高效的方式是在onAccessibilityEvent()里先把需要的属性提取出来,封装成自定义实体类再传给AsyncTask。这种方式避免了对象复制的开销,也不用处理回收逻辑。

示例代码:

// 自定义实体类,存储需要的事件属性
class AccessibilityEventData {
    long eventTime;
    String packageName;
    // 可以添加其他你需要的属性,比如事件类型、文本内容等
}

public class MyAccessibilityService extends AccessibilityService { 
    public void onAccessibilityEvent(AccessibilityEvent event) { 
        AccessibilityEventData eventData = new AccessibilityEventData();
        // 提前提取属性
        eventData.eventTime = event.getEventTime();
        if (event.getPackageName() != null) {
            eventData.packageName = event.getPackageName().toString();
        }
        // 提取其他需要的属性...
        
        new MyTestAsync().execute(eventData); 
    } 

    public class MyTestAsync extends AsyncTask<AccessibilityEventData, Void, Void> { 

        @Override 
        protected Void doInBackground(AccessibilityEventData... params) { 
            AccessibilityEventData data = params[0]; 
            // 直接使用data里的属性,完全不会有丢失问题
            return null; 
        } 
    } 
}

内容的提问来源于stack exchange,提问作者Nikhil

火山引擎 最新活动