应用简要说明:
- 我有用于本地代码执行的 Cordova/Ionic 应用程序和自定义 Cordova 插件。
- 插件包含单独的 CameraActivity(扩展 FragmentActivity)以使用 Camera(部分代码基于 Camera2Basic 示例)。
- 启动时 Activity 显示 AnaliseFragment,应用程序在其中捕获每个 Camera 帧并将图像传递给后台线程上的分析器。
执行步骤为:
- 用户按下 Cordova UI 上的按钮
- Cordova 通过 cordova.exec(..) 执行本机插件方法
- 本机插件通过 cordova.startActivityForResult(..) 启动 CameraActivity 以获得结果
- CameraActivity 显示 AnaliseFragment
- AnaliseFragment 使用两个表面启动相机捕获会话:第一个显示在 TextureView 上,第二个由 ImageAnaliser 分析
问题:
UI 很少且随机地停止对用户和未在 UI 线程上执行的可运行对象做出反应。与此同时,后台线程继续正常工作:在 TextureView 上可以看到相机输出,并且 ImageAnaliser 继续从相机接收图像。
有没有人有任何建议如何找到/调试这种行为的原因?或者有什么想法会导致这种情况?
我已经尝试过:
- 记录 CameraActivity/AnaliseFragment 的每个生命周期事件 = 应用正常状态和 ANR 之间没有调用
- 添加 WAKELOCK 以保持 Cordova MainActivity 活动 = 没有帮助
- 记录(跟踪) AnalilseFragment 和 ImageAnaliser 中的每个方法 = 没什么可疑的
下面是 AnaliseFragment 的简化代码:
public class AnaliseFragment extends Fragment {
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private ImageAnalyser mImageAnalyser;
// listener is attached to camera capture session and receives every frame
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image nextImage = reader.acquireLatestImage();
mBackgroundHandler.post(() ->
try {
mImageAnalyser.AnalizeNextImage(mImage);
}
finally {
mImage.close();
}
);
}
};
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
mImageAnalyser = new ImageAnalyser();
mImageAnalyser.onResultAvailable(boolResult -> {
// Runnable posted, but never executed
new Handler(Looper.getMainLooper()).post(() -> reportToActivityAndUpdateUI(boolResult));
});
}
@Override
public void onResume() {
super.onResume();
startBackgroundThread();
}
@Override
public void onPause() {
stopBackgroundThread();
super.onPause();
}
private void startBackgroundThread() {
if (mBackgroundThread == null) {
mBackgroundThread = new HandlerThread("MyBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ImageAnalyser 的简化代码:
public class ImageAnalyser {
public interface ResultAvailableListener {
void onResult(bool boolResult);
}
private ResultAvailableListener mResultAvailableListener;
public void onResultAvailable(ResultAvailableListener listener) { mResultAvailableListener = listener; }
public void AnalizeNextImage(Image image) {
// Do heavy analysis and put result into theResult
mResultAvailableListener.onResult(theResult);
}
}