Android -- Camera源码简析,启动流程
com.android.camera.Camera.java,主要的实现Activity,继承于ActivityBase。
ActivityBase
在ActivityBase中执行流程:
- onCreate中进行判断是否是平板;
- onResume中判断是否锁屏,锁屏&camera不存在时候,mOnResumePending置为true,否则置为false并执行doOnResume;
- onWindowFocusChanged中判断是否获取到焦点&mOnResumePending,满足的话执行doOnResume;
- 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;
我是天王盖地虎的分割线
Android -- Camera源码简析,启动流程的更多相关文章
- Flink源码阅读(一)——Flink on Yarn的Per-job模式源码简析
一.前言 个人感觉学习Flink其实最不应该错过的博文是Flink社区的博文系列,里面的文章是不会让人失望的.强烈安利:https://ververica.cn/developers-resource ...
- SpringMVC学习(一)——概念、流程图、源码简析
学习资料:开涛的<跟我学SpringMVC.pdf> 众所周知,springMVC是比较常用的web框架,通常整合spring使用.这里抛开spring,单纯的对springMVC做一下总 ...
- django-jwt token校验源码简析
一. jwt token校验源码简析 1.1 前言 之前使用jwt签发了token,里面的头部包含了加密的方式.是否有签名等,而载荷中包含用户名.用户主键.过期时间等信息,最后的签名还使用了摘要算法进 ...
- Appium Android Bootstrap源码分析之启动运行
通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...
- 0002 - Spring MVC 拦截器源码简析:拦截器加载与执行
1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日 ...
- Python Web Flask源码解读(一)——启动流程
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- Flume-ng源码解析之启动流程
今天我们通过阅读Flume-NG的源码来看看Flume的整个启动流程,废话不多说,翠花,上源码!! 1 主类也是启动类 在这里我贴出Application中跟启动有关的方法,其他你们可以自己看源码,毕 ...
- AFNetworking源码简析
AFNetworking基本是苹果开发中网络请求库的标配,它是一个轻量级的网络库,专门针对iOS和OS X的网络应用设计,具有模块化的架构和丰富的APIs接口,功能强大并且使用简单,深受苹果应用开发人 ...
- SpringMVC源码解析-DispatcherServlet启动流程和初始化
在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从Dis ...
随机推荐
- JAVA基础部分面试
1:面向对象编程有很多重要的特性: 封装,继承,多态和抽象. 2:什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? (1)Java虚拟机是一个可以执行Java字节码的虚拟机进程.J ...
- Form与ModelForm-下拉框或者多选注意//及字段补充
一.Form 设计一张普通model表: class UserInfo(models.Model): name = models.CharField(verbose_name='员工姓名', max_ ...
- ASP.net 简单分页的实现
在自己的项目中有一个文章的管理页面需要用到分页, 这种分页方法是在黑马的一个视频中看到的,便用在了自己的项目中. 但是使用控件实在是太丑,虽然我写的也丑....... gridview 控件提供的分页 ...
- 第一个ASP.NET MVC应用程序
首先打开vs2015 文件->新建->项目 选择模版选empty,下面[为下项添加文件夹和核心引用]勾选mvc 点击确定就好
- 「HNOI2018」毒瘤
「HNOI2018」毒瘤 解题思路 先考虑只有一棵树的情况,经典独立集计数. \[ dp[u][0]=\prod (dp[v][0]+dp[v][1]) \\ dp[u][1]=\prod dp[v] ...
- poj 3463 最短路+次短路
独立写查错不能,就是维护一个次短路的dist 题意:给定一个有向图,问从起点到终点,最短路+比最短路距离长1的路的个数. Sample Input25 81 2 31 3 21 4 52 3 12 5 ...
- 【洛谷】2473:[SCOI2008]奖励关【期望DP(倒推)】
P2473 [SCOI2008]奖励关 题目背景 08四川NOI省选 题目描述 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不 ...
- BZOJ 1196: [HNOI2006]公路修建问题 Kruskal/二分
1196: [HNOI2006]公路修建问题 Time Limit: 1 Sec Memory Limit: 162 MB 题目连接 http://www.lydsy.com/JudgeOnline ...
- vue 组件开发 props 验证
使用props 在Vue中父组件向子组件中传送数据是通过props实现的,一个简单的使用props的例子: <!DOCTYPE html> <html> <head> ...
- 【原】Java程序调用远程Shell脚本
此程序的目的是执行远程机器上的Shell脚本. [环境参数]远程机器IP:192.168.234.123用户名:root密码:rootShell脚本的路径:/home/IFileGenTool/Bak ...