首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >SurfaceHolder回调与活动生命周期有何关系?

SurfaceHolder回调与活动生命周期有何关系?
EN

Stack Overflow用户
提问于 2012-07-16 05:40:51
回答 5查看 45.5K关注 0票数 73

我一直在尝试实现一个需要在表面上进行相机预览的应用程序。在我看来,活动和表面生命周期都由以下状态组成:

当我第一次启动我的Activity:onResume()->onSurfaceCreated()->onSurfaceChanged()

  • When时,我离开了我的Activity:onPause()->onSurfaceDestroyed()

在这个方案中,我可以在onPause/onResumeonSurfaceCreated()/onSurfaceDestroyed()中进行相应的调用,如打开/释放摄像头和启动/停止预览。

它工作得很好,除非我锁定屏幕。当我启动应用程序,然后锁定屏幕并在稍后解锁时,我看到:

onPause() -在屏幕被锁定之后没有其他东西-解锁之后是onResume() -在那之后没有表面回调。实际上,onResume()是在按下电源按钮并打开屏幕后调用的,但锁定屏幕仍处于活动状态,因此,它甚至在活动变得可见之前。

使用此方案,解锁后会出现黑屏,并且不会调用任何表面回调。

这是一个代码片段,它不涉及相机的实际工作,但涉及SurfaceHolder回调。即使在我的手机上使用这个代码,上面的问题也会重现(当你按下“后退”按钮时,回调是按正常顺序进行的,但当你锁定屏幕时,回调就会消失):

代码语言:javascript
复制
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");
    }
}

有什么想法可以解释为什么在活动暂停后,表面仍未被破坏?另外,在这种情况下,您如何处理摄像头的生命周期?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-12-03 00:47:18

编辑:如果targetSDK大于10,则将应用程序置于睡眠状态,调用onPauseonStopSource

我在我的姜饼手机上的一个小相机应用程序中查看了Activity和SurfaceView的生命周期。你完全正确;当按下电源按钮使手机进入睡眠状态时,表面不会被破坏。当手机进入睡眠状态时,该活动会执行onPause。(并且不执行onStop。)它会在手机唤醒时执行onResume,正如您所指出的,在锁定屏幕仍然可见并接受输入的情况下,它会执行此操作,这有点奇怪。当我通过按Home按钮使Activity不可见时,Activity同时执行onPauseonStop。在这种情况下,在onPause的结尾和onStop的开头之间,会有一个对surfaceDestroyed的回调。这不是很明显,但它确实看起来非常一致。

当按下电源按钮使手机休眠时,除非采取明确的措施来阻止它,否则摄像头会继续运行!如果我让摄像头为每个预览帧执行每幅图像的回调,并在其中添加Log.d(),则在手机假装睡眠时,日志语句会不断出现。我认为这是非常滑稽的。

作为另一种混淆,如果正在创建表面,则在activity中的onResume之后会回调surfaceCreatedsurfaceChanged

通常,我在实现SurfaceHolder回调的类中管理相机。

代码语言:javascript
复制
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;
       }
   }
}

然后在练习中:

代码语言:javascript
复制
@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被销毁并重新创建。

票数 59
EN

Stack Overflow用户

发布于 2014-05-21 22:44:28

另一个有效的简单解决方案-更改预览曲面的可见性。

代码语言:javascript
复制
private SurfaceView preview;

预览在onCreate方法中初始化。在onResume方法中,为预览曲面设置View.VISIBLE

代码语言:javascript
复制
@Override
public void onResume() {
    preview.setVisibility(View.VISIBLE);
    super.onResume();
}

和分别在onPause集合可见性View.GONE

代码语言:javascript
复制
@Override
public void onPause() {
    super.onPause();
    preview.setVisibility(View.GONE);
    stopPreviewAndFreeCamera(); //stop and release camera
}
票数 22
EN

Stack Overflow用户

发布于 2015-03-10 22:29:09

多亏了前面的两个答案,我成功地让我的相机预览在从背景或锁屏返回时能正常工作。

正如@e7fendy提到的,在屏幕锁定时不会调用SurfaceView的回调,因为系统仍然可以看到表面视图。

因此,正如@validcat建议的那样,分别在onPause()和onResume()中调用preview.setVisibility(View.VISIBLE);preview.setVisibility(View.GONE);将强制表面视图重新布局自身,并将调用它的回调。

到那时,@emrys57的解决方案加上上面这两个可见性方法调用将使你的相机预览工作简单:)

所以我只能给你们每个人+1,因为你们都是应得的;)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11495842

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档