Android -- Camera源码简析,启动流程

com.android.camera.Camera.java,主要的实现Activity,继承于ActivityBase。

ActivityBase

在ActivityBase中执行流程:

  1. onCreate中进行判断是否是平板;
  2. onResume中判断是否锁屏,锁屏&camera不存在时候,mOnResumePending置为true,否则置为false并执行doOnResume;
  3. onWindowFocusChanged中判断是否获取到焦点&mOnResumePending,满足的话执行doOnResume;
  4. onPause中将mOnResumePending置为false;

Camera.java

接下来分析Camera.java,执行流程:

1、onCreate

// 获得摄像头的数量,前置和后置
getPreferredCameraId();
// 获得对焦设置eg:连续对焦或者其它
String[] defaultFocusModes = getResources().getStringArray(R.array.pref_camera_focusmode_default_array);
//实例化Focus管理对象
mFocusManager = new FocusManager(mPreferences, defaultFocusModes);
// 开启线程来启动摄像头
mCameraOpenThread.start();
// 是否是第三方应用启动拍照功能
mIsImageCaptureIntent = isImageCaptureIntent();
// 设置UI布局文件
setContentView(R.layout.camera);
if (mIsImageCaptureIntent) {
       // 当第三方其送拍照,需要显示不同的UI,比如取消键盘
       mReviewDoneButton = (Rotatable) findViewById(R.id.btn_done);
       mReviewCancelButton = (Rotatable) findViewById(R.id.btn_cancel);
       findViewById(R.id.btn_cancel).setVisibility(View.VISIBLE);
} else {
       // 反之显示缩略图
       mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail);
       mThumbnailView.enableFilter(false);
       mThumbnailView.setVisibility(View.VISIBLE);
}
// 一个能旋转的dialog.比如相机设置的dialog,这个类实现了旋转的父类
mRotateDialog = new RotateDialogController(this, R.layout.rotate_dialog);
// 设置camera的ID,写道SharedPreference中
mPreferences.setLocalId(this, mCameraId);
// 更新preference
CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
// 获得相机数
mNumberOfCameras = CameraHolder.instance().getNumberOfCameras();
//  貌似是获得是否是快速拍照
mQuickCapture = getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
// 为当前的preview重置曝光值
resetExposureCompensation();
// 隐藏系统导航栏等
Util.enterLightsOutMode(getWindow());
//SurfaceView
SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview);
SurfaceHolder holder = preview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
try {
       // 这个join语句就是为了保证openCamera的线程执行完后,当前的线程才开始运行。主要是为了确保camera设备被打开了
        mCameraOpenThread.join();
        // 线程执行完后置为空来让系统回收资源
        mCameraOpenThread = null;
        if (mOpenCameraFail) {
            // 打开camera失败,显示“无法连接到相机”
            Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
            return;
        } else if (mCameraDisabled) {
            // 由于安全政策限制,相机已被停用
            Util.showErrorAndFinish(this, R.string.camera_disabled);
            return;
        }
} catch (InterruptedException ex) {
           // ignore
}
//开启显示的子线程
mCameraPreviewThread.start();
if (mIsImageCaptureIntent) {
    //如果是第三方开启的 ,setupCaptureParams 设置拍照的参数
     setupCaptureParams();
} else {
      //设置ModePicker
      mModePicker = (ModePicker) findViewById(R.id.mode_picker);
      mModePicker.setVisibility(View.VISIBLE);
      mModePicker.setOnModeChangeListener(this);
      mModePicker.setCurrentMode(ModePicker.MODE_CAMERA);
}
mZoomControl = (ZoomControl) findViewById(R.id.zoom_control);
mOnScreenIndicators = (Rotatable) findViewById(R.id.on_screen_indicators);
mLocationManager = new LocationManager(this, this);
//摄像头ID
mBackCameraId = CameraHolder.instance().getBackCameraId();
mFrontCameraId = CameraHolder.instance().getFrontCameraId();
// 在startPreview里面有notify方法
synchronized (mCameraPreviewThread) {
      try {
          mCameraPreviewThread.wait();
       } catch (InterruptedException ex) {
            // ignore
       }
}
// 初始化各种控制按钮
initializeIndicatorControl();
//初始化拍照声音
mCameraSound = new CameraSound();
try {
       //确保显示
       mCameraPreviewThread.join();
} catch (InterruptedException ex) {
        // ignore
}
mCameraPreviewThread = null;

2、surfaceCreated

啥都没做

3、surfaceChanged

// 确保在holder中有surface
 if (holder.getSurface() == null) {
       Log.d(TAG, "holder.getSurface() == null");
        return;
}
// We need to save the holder for later use, even when the mCameraDevice
// is null. This could happen if onResume() is invoked after this
// function.
mSurfaceHolder = holder;
if (mCameraDevice == null) return;
if (mPausing || isFinishing()) return;
// Set preview display if the surface is being created. Preview was
// already started. Also restart the preview if display rotation has
// changed. Sometimes this happens when the device is held in portrait
// and camera app is opened. Rotation animation takes some time and
// display rotation in onCreate may not be what we want.
if (mCameraState == PREVIEW_STOPPED) {
        startPreview();
        startFaceDetection();
} else {
        if (Util.getDisplayRotation(this) != mDisplayRotation) {
            setDisplayOrientation();
}
        if (holder.isCreating()) {
            // Set preview display if the surface is being created and preview
            // was already started. That means preview display was set to null
            // and we need to set it now.
            setPreviewDisplay(holder);
        }
}
// If first time initialization is not finished, send a message to do
// it later. We want to finish surfaceChanged as soon as possible to let
// user see preview first.
if (!mFirstTimeInitialized) {
       mHandler.sendEmptyMessage(FIRST_TIME_INIT);
} else {
      initializeSecondTime();
 }

如果是第一次加载,则执行mHandler.sendEmptyMessage(FIRST_TIME_INIT); 对应处理的是initializeFirstTime();

/**
     * 初始化,第一次初始化
     *  // Snapshots can only be taken after this is called. It should be called
     *  // once only. We could have done these things in onCreate() but we want to
     *  // make preview screen appear as soon as possible.
     */
    private void initializeFirstTime() {
        if (mFirstTimeInitialized) return;

        // Create orientation listenter. This should be done first because it
        // takes some time to get first orientation.
        mOrientationListener = new MyOrientationEventListener(Camera.this);
        mOrientationListener.enable();

        // Initialize location sevice.
        boolean recordLocation = RecordLocationPreference.get(
                mPreferences, getContentResolver());
        // 初始化屏幕最上方的标志,比如开启了曝光值啊,什么的
        initOnScreenIndicator();
        // 位置服务
        mLocationManager.recordLocation(recordLocation);

        keepMediaProviderInstance();
        // 检查存储空间和初始化储存目录
        checkStorage();
        // Initialize last picture button.
        mContentResolver = getContentResolver();
        if (!mIsImageCaptureIntent) {  // no thumbnail in image capture intent
            // 初始化缩略图
            initThumbnailButton();
        }
        // Initialize shutter button.
        // 初始化拍照按钮并设置监听事件
        mShutterButton = (ShutterButton) findViewById(R.id.shutter_button);
        mShutterButton.setOnShutterButtonListener(this);
        mShutterButton.setVisibility(View.VISIBLE);
        // Initialize focus UI.
        mPreviewFrame = findViewById(R.id.camera_preview);
        mPreviewFrame.setOnTouchListener(this);
        // 聚焦框
        mFocusAreaIndicator = (RotateLayout) findViewById(R.id.focus_indicator_rotate_layout);
        CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
        boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
        mFocusManager.initialize(mFocusAreaIndicator, mPreviewFrame, mFaceView, this,
                mirror, mDisplayOrientation);
        // 初始化一个图片的保存线程
        mImageSaver = new ImageSaver();
        // 设置屏幕亮度
        Util.initializeScreenBrightness(getWindow(), getContentResolver());
        // 注册SD卡相关的广播,比如拔出存储卡什么的
        installIntentFilter();
        // 初始化缩放UI
        initializeZoom();
        // 更新屏幕上的闪光灯什么的标记
        updateOnScreenIndicators();
        // 开始面部检测
        startFaceDetection();
        // Show the tap to focus toast if this is the first start.
        // 假如是第一次启动,提示用户“触摸对焦”
        if (mFocusAreaSupported &&
                mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
            // Delay the toast for one second to wait for orientation.
            mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
        }
        mFirstTimeInitialized = true;
        addIdleHandler();
    }

如果不是,则执行initializeSecondTime();

/**
     *  // If the activity is paused and resumed, this method will be called in
     *  // onResume.
     */
    private void initializeSecondTime() {
        // Start orientation listener as soon as possible because it takes
        // some time to get first orientation.
        //方向翻转设置enable,其中包括翻转的时候的动画
        mOrientationListener.enable();

        // Start location update if needed.
        boolean recordLocation = RecordLocationPreference.get(
                mPreferences, getContentResolver());
        mLocationManager.recordLocation(recordLocation);
        //设置SD卡广播
        installIntentFilter();
        mImageSaver = new ImageSaver();
        //初始化Zoom
        initializeZoom();
        //mMediaProviderClient=媒体Provider对象
        keepMediaProviderInstance();
        //检查硬盘
        checkStorage();
        //淡出retake和done的Button
        hidePostCaptureAlert();
        if (!mIsImageCaptureIntent) {
            //如果不是第三方开启,则更新缩略图
            updateThumbnailButton();
            mModePicker.setCurrentMode(ModePicker.MODE_CAMERA);
        }
    }

4、surfaceDestroyed

stopPreview();
mSurfaceHolder = null;

我是天王盖地虎的分割线

时间: 2024-11-08 21:56:44

Android -- Camera源码简析,启动流程的相关文章

SpringMVC学习——概念、流程图、源码简析(一)

学习资料:开涛的<跟我学SpringMVC.pdf> 众所周知,springMVC是比较常用的web框架,通常整合spring使用.这里抛开spring,单纯的对springMVC做一下总结. 概念 HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象) HandlerAdapter:处理器适配器,适配不同类型的处理器,如Cont

并发工具-CyclicBarrier源码简析

CyclicBarrier是循环栅栏的意思,循环的等待多个线程执行任务: <1> 示例代码如下: public class CyclicBarrierTest { public static CyclicBarrier cb = new CyclicBarrier(3, () -> System.out.println("-------开始点名-------")); public static void main(String[] args) { System.out

0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日志.判断用户是否登录等. 2.简单示例 2.1.继承 HandlerInterceptorAdapter 抽象类实现一个拦截器.代码如下: public class DemoInterceptor extends HandlerInterceptorAdapter { @Override    pu

SpringMVC源码解析-DispatcherServlet启动流程和初始化

在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从DispatcherServlet入手,从名字来看,它是一个Servlet.它的定义如下: public class DispatcherServlet extends FrameworkServlet { 它是继承FrameworkServlet,来看一下整个的继承关系. 从继承关系来看,Dispatc

JDK源码简析--java.lang包中的基础类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.lang包所包

JDK源码简析--java.util包中的工具类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.util包所包

Linux Hugetlbfs内核源码简析-----(一)Hugetlbfs初始化

一.引言 为了实现虚拟内存管理机制,操作系统对内存实行分页管理.自内存“分页机制”提出之始,内存页面的默认大小便被设置为 4096 字节(4KB),虽然原则上内存页面大小是可配置的,但绝大多数的操作系统实现中仍然采用默认的 4KB 页面.当某些应用的需要使用的内存达到几G.甚至几十G的时候,4KB的内存页面将严重制约程序的性能. CPU缓存中有一组缓存专门用于缓存TLB,但其大小是有限的.当采用的默认页面大小为 4KB,其产生的TLB较大,因而将会产生较多 TLB Miss 和缺页中断,从而大大

[tomcat]源码简析 异步/非阻塞和请求构成

提出疑惑 SpringFramework5.0又新增加了一个功能Webflux(响应式编程),是一个典型非阻塞异步的框架.我们知道servlet3.0实现异步(AsyncContext),servlet3.1又提出了非阻塞IO.对此我一直有两点疑惑:1.tomcat8底层已经默认使用NIO了,不是已经是IO非阻塞了吗,怎么又说servlet3.1解决了非阻塞.2.关于异步,如果开发者在serlvet中开一个业务线程来实现,也算异步,为什么3.0还提供了一个组件来解决,那么这种方式和开发者自己开个

Spring源码分析: SpringMVC启动流程与DispatcherServlet请求处理流程

Spring版本: 4.0.X 注:这里的分析只关注整个处理流程的大致过程,省略与流程无关的代码. 应用根上下文(Root ApplicationContext)的启动 我们知道在一个web项目中使用SpringMVC时,需在web.xml中配置一个监听器: <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </list