从Camera
获取到了byte[]
类型的图像数据之后,需要送到so库中,让so库进行相应的处理,并对其处理的结果进行相应的反馈;1s大概有30帧的数据,但是除去一些装载数据的事件,时间就变大了,实际可拿到的帧率就变小了;在此每秒取5帧,每张图片大致1~3M。这大致就是解决这个问题的背景框架。
起因
处理图片时,耗时较长,放在主线程中,会造成卡顿,严重的时候会造成ANR。但是算法库处理时,会依赖于上一帧的数据,所以还是要按照顺序,一帧一帧来处理。
从Camera
取数据后,立即开启线程处理的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| mCamera.addCallbackBuffer(new byte[size.width * size.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8]); mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { if (mCallback != null && mCamera != null){ mCallback.onImageAvaliable(data, size.width, size.height); mCamera.addCallbackBuffer(new byte[size.width * size.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8]); } } });
ExecutorService pool = Executors.newSingleThreadExecutor(); ... if (isSwitchOn(R.id.fall_detect)) { pool.execute(new CheckFallAndMoveThread(buf, width, height)); }
|
这样的话,只允许一个线程执行,多来了的,就排队等待处理,这样便实现了一帧一帧处理,并且还不会阻塞主线程。但是很可惜,这样会造成OOM。
原因
so库处理的时间达到了2s左右(处理的图片没有经过resize),有点长。这样的话,每个需要处理的Runnable
都需要一定的空间去存储这个图片,并且此种Executor是Runnable
是无限长的,长度会自动变化,空间很快就会用完,也是合情合理。
解决办法
看了一下,默认提供的几种线程池,并不能达到自己的需求,只能自己重新设置一下其中的参数,然后利用这些参数,设置成自己想要的那种模式,即队列长度有限,按顺序执行,然后宁愿少处理几帧,也要避免OOM。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class CalTaskThreadExecutor { private static final ExecutorService instance = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "SingleTaskPoolThread #" + mCount.getAndIncrement()); } }, new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { Log.e("TAG", "超了"); executor.remove(r); } }); public static ExecutorService getInstance(){ return instance; } }
|
十分感谢这篇博客,让我大致明白了其中参数所代表的意义,并按照自己的需求整个相应线程池出来。线程池,这一篇或许就够了。