【发布时间】:2019-04-12 08:11:46
【问题描述】:
申请简介:
- 我有用于执行本机代码的 Cordova/Ionic 应用程序和自定义 Cordova 插件。
- 插件包含单独的 CameraActivity(扩展 FragmentActivity)以使用 Camera(部分代码基于 Camera2Basic 示例)。
- 在启动 Activity 时会显示 AnaliseFragment,应用程序会在其中捕获每个 Camera 帧并将图像通过后台线程传递给分析器。
执行步骤为:
- 用户在 Cordova 用户界面上按下按钮
- 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);
}
}
【问题讨论】:
-
你释放图片资源吗?我没有看到任何致电
https://developer.android.com/reference/android/media/Image.html#close() -
是的,我在需要的地方在 finally 块中调用 close() 方法。如果不调用,我将无法获得比相机捕获会话缓冲区更多的图像。我更新了代码示例,看看如何调用 close() 方法
-
也许你的结果永远不可用..
-
我在 onResultAvailable 和 reportToActivityAndUpdateUI 的第一行添加了日志记录,在 Logcat 中看到,调用了 onResultAvailable,但没有调用 reportToActivityAndUpdateUI。
-
您只能通过
mImageAnalyser.onResultAvailable在 onViewCreated 中分派一次结果。您应该在处理完每个图像后立即发送结果。
标签: android cordova cordova-plugins android-looper android-threading