我一直在尝试实现一个需要在表面上进行相机预览的应用程序。在我看来,活动和表面生命周期都由以下状态组成:
当我第一次启动我的Activity:onResume()->onSurfaceCreated()->onSurfaceChanged()
onPause()->onSurfaceDestroyed()
在这个方案中,我可以在onPause/onResume
和onSurfaceCreated()/onSurfaceDestroyed()
中进行相应的调用,如打开/释放摄像头和启动/停止预览。
它工作得很好,除非我锁定屏幕。当我启动应用程序,然后锁定屏幕并在稍后解锁时,我看到:
onPause()
-在屏幕被锁定之后没有其他东西-解锁之后是onResume()
-在那之后没有表面回调。实际上,onResume()
是在按下电源按钮并打开屏幕后调用的,但锁定屏幕仍处于活动状态,因此,它甚至在活动变得可见之前。
使用此方案,解锁后会出现黑屏,并且不会调用任何表面回调。
这是一个代码片段,它不涉及相机的实际工作,但涉及SurfaceHolder
回调。即使在我的手机上使用这个代码,上面的问题也会重现(当你按下“后退”按钮时,回调是按正常顺序进行的,但当你锁定屏幕时,回调就会消失):
class Preview extends SurfaceView implements SurfaceHolder.Callback {
private static final String tag= "Preview";
public Preview(Context context) {
super(context);
Log.d(tag, "Preview()");
SurfaceHolder holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(tag, "surfaceCreated");
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(tag, "surfaceDestroyed");
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.d(tag, "surfaceChanged");
}
}
有什么想法可以解释为什么在活动暂停后,表面仍未被破坏?另外,在这种情况下,您如何处理摄像头的生命周期?
发布于 2012-12-03 00:47:18
编辑:如果targetSDK大于10,则将应用程序置于睡眠状态,调用onPause
和onStop
。Source
我在我的姜饼手机上的一个小相机应用程序中查看了Activity和SurfaceView的生命周期。你完全正确;当按下电源按钮使手机进入睡眠状态时,表面不会被破坏。当手机进入睡眠状态时,该活动会执行onPause
。(并且不执行onStop
。)它会在手机唤醒时执行onResume
,正如您所指出的,在锁定屏幕仍然可见并接受输入的情况下,它会执行此操作,这有点奇怪。当我通过按Home按钮使Activity不可见时,Activity同时执行onPause
和onStop
。在这种情况下,在onPause
的结尾和onStop
的开头之间,会有一个对surfaceDestroyed
的回调。这不是很明显,但它确实看起来非常一致。
当按下电源按钮使手机休眠时,除非采取明确的措施来阻止它,否则摄像头会继续运行!如果我让摄像头为每个预览帧执行每幅图像的回调,并在其中添加Log.d(),则在手机假装睡眠时,日志语句会不断出现。我认为这是非常滑稽的。
作为另一种混淆,如果正在创建表面,则在activity中的onResume
之后会回调surfaceCreated
和surfaceChanged
。
通常,我在实现SurfaceHolder回调的类中管理相机。
class Preview extends SurfaceView implements SurfaceHolder.Callback {
private boolean previewIsRunning;
private Camera camera;
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
// ...
// but do not start the preview here!
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// set preview size etc here ... then
myStartPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
myStopPreview();
camera.release();
camera = null;
}
// safe call to start the preview
// if this is called in onResume, the surface might not have been created yet
// so check that the camera has been set up too.
public void myStartPreview() {
if (!previewIsRunning && (camera != null)) {
camera.startPreview();
previewIsRunning = true;
}
}
// same for stopping the preview
public void myStopPreview() {
if (previewIsRunning && (camera != null)) {
camera.stopPreview();
previewIsRunning = false;
}
}
}
然后在练习中:
@Override public void onResume() {
preview.myStartPreview(); // restart preview after awake from phone sleeping
super.onResume();
}
@Override public void onPause() {
preview.myStopPreview(); // stop preview in case phone is going to sleep
super.onPause();
}
这对我来说似乎没什么问题。循环事件会导致活动被销毁并重新创建,这也会导致SurfaceView被销毁并重新创建。
发布于 2014-05-21 22:44:28
另一个有效的简单解决方案-更改预览曲面的可见性。
private SurfaceView preview;
预览在onCreate
方法中初始化。在onResume
方法中,为预览曲面设置View.VISIBLE
:
@Override
public void onResume() {
preview.setVisibility(View.VISIBLE);
super.onResume();
}
和分别在onPause
集合可见性View.GONE
中
@Override
public void onPause() {
super.onPause();
preview.setVisibility(View.GONE);
stopPreviewAndFreeCamera(); //stop and release camera
}
发布于 2015-03-10 22:29:09
多亏了前面的两个答案,我成功地让我的相机预览在从背景或锁屏返回时能正常工作。
正如@e7fendy提到的,在屏幕锁定时不会调用SurfaceView的回调,因为系统仍然可以看到表面视图。
因此,正如@validcat建议的那样,分别在onPause()和onResume()中调用preview.setVisibility(View.VISIBLE);
和preview.setVisibility(View.GONE);
将强制表面视图重新布局自身,并将调用它的回调。
到那时,@emrys57的解决方案加上上面这两个可见性方法调用将使你的相机预览工作简单:)
所以我只能给你们每个人+1,因为你们都是应得的;)
https://stackoverflow.com/questions/11495842
复制相似问题