文末
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。
当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
进阶学习视频
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
@Override
public void run() {
camera.setCameraFacing(facing);
}
});
}
@Override
public int getCameraFacing() {
return camera.getCameraFacing();
}
@Override
public void setPreviewSize(Size cameraSize) {
postTask(new Runnable() {
@Override
public void run() {
camera.setPreviewSize(cameraSize);
}
});
}
@Override
public Size getPreviewSize() {
return camera.getPreviewSize();
}
@Override
public void setDisplayOrientation(int displayOrientation) {
postTask(new Runnable() {
@Override
public void run() {
camera.setDisplayOrientation(displayOrientation);
}
});
}
@Override
public int getDisplayOrientation() {
return camera.getDisplayOrientation();
}
@Override
public void releaseCamera() {
if (handler == null) {
return;
}
postTask(new Runnable() {
@Override
public void run() {
camera.releaseCamera();
stopBackground();
}
});
}
@Override
public void addOnCameraListener(OnCameraListener onCameraListener) {
postTask(new Runnable() {
@Override
public void run() {
camera.addOnCameraListener(onCameraListener);
}
});
}
@Override
public void removeOnCameraListener(OnCameraListener onCameraListener) {
postTask(new Runnable() {
@Override
public void run() {
camera.removeOnCameraListener(onCameraListener);
}
});
}
@Override
public void removeAllOnCameraListener() {
postTask(new Runnable() {
@Override
public void run() {
camera.removeAllOnCameraListener();
}
});
}
/**
- 获取Handler
*/
private Handler getHandler() {
if (thread == null || handler == null) {
startBackground();
}
return handler;
}
/**
- 开启线程
*/
private void startBackground() {
stopBackground();
thread = new HandlerThread(“camera_manager”);
thread.start();
handler = new Handler(thread.getLooper());
}
/**
- 关闭线程
*/
private void stopBackground() {
if (thread != null) {
thread.quitSafely();
thread = null;
}
if (handler != null) {
handler = null;
}
}
/**
- 执行任务
*/
private void postTask(Runnable runnable) {
getHandler().post(runnable);
}
}
注意到,CameraManager
内部开启了Handler
,目的是让相机的相关操作都在子线程进行
接下来可以具体实现Camera1
同样,我们新建Camera1
,并实现ICamera
接口
三、Camera1
全局变量
/**
- Camera
/
private Camera camera;
/* - 预览尺寸
/
private Size cameraSize = new Size(-1, -1);
/* - 默认摄像头方向
/
private int facing = CameraConstants.facing.BACK;
/* - 旋转角度
*/
private int displayOrientation = -1;
打开相机
public void openCamera(int facing, Activity activity, SurfaceTexture surfaceTexture) {
// 先关闭相机
closeCamera();
// 判断是否存在摄像头
int cameraNum = Camera.getNumberOfCameras();
if (cameraNum <= 0) {
onCameraError(new IllegalStateException(“camera num <= 0”));
return;
}
// 检查传入的facing
int cameraIndex = -1;
if (facing == CameraConstants.facing.BACK) {
cameraIndex = Camera.CameraInfo.CAMERA_FACING_BACK;
} else if (facing == CameraConstants.facing.FRONT) {
cameraIndex = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
if (cameraIndex == -1) {
onCameraError(new IllegalStateException(“camera facing exception”));
return;
}
// 判断摄像头个数,以决定使用哪个打开方式
if (cameraNum >= 2) {
camera = Camera.open(cameraIndex);
} else {
camera = Camera.open();
}
// 判断Camera是否初始化成功
if (camera == null) {
onCameraError(new IllegalStateException(“camera is null”));
return;
}
this.facing = facing;
try {
// 获取摄像头参数
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
if (cameraSize.getWidth() <= 0 || cameraSize.getHeight() <= 0) {
Camera.Size size = findTheBestSize(previewSizeList,
activity.getResources().getDisplayMetrics().widthPixels,
activity.getResources().getDisplayMetrics().heightPixels);
cameraSize.setWidth(size.width);
cameraSize.setHeight(size.height);
}
// 设置预览尺寸
parameters.setPreviewSize(cameraSize.getWidth(), cameraSize.getHeight());
// 这里设置使用的对焦模式
if (this.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
// 设置摄像头参数
camera.setParameters(parameters);
camera.setPreviewTexture(surfaceTexture);
if (displayOrientation < 0) {
displayOrientation = CameraUtils.getDisplayOrientation(activity, cameraIndex);
}
camera.setDisplayOrientation(displayOrientation);
camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
onCameraOpened(cameraSize, Camera1.this.facing);
}
});
camera.startPreview();
} catch (IOException e) {
onCameraError(e);
}
}
注意到,在对相机参数设置的时候,使用findTheBestSize
方法进行选择最佳的尺寸,该方法不是Android
原生提供的,是根据相机所支持的所有预览尺寸和当前屏幕的尺寸所计算得到的
private Camera.Size findTheBestSize(List<Camera.Size> sizeList, int screenW, int screenH) {
if (sizeList == null || sizeList.isEmpty()) {
throw new IllegalArgumentException();
}
Log.d(TAG, “findTheBestSize: screenW:” + screenW + " screenH:" + screenH);
Camera.Size bestSize = sizeList.get(0);
for (Camera.Size size : sizeList) {
int width = size.height;
int height = size.width;
Log.d(TAG, “findTheBestSize: width:” + width + " height:" + height);
float ratioW = (float) width / screenW;
float ratioH = (float) height / screenH;
Log.d(TAG, “findTheBestSize: ratioW:” + ratioW + " ratioH:" + ratioH);
if (ratioW == ratioH) {
bestSize = size;
break;
}
}
return bestSize;
}
还注意到,设置相机旋转角度时,有用到CameraUtils.getDisplayOrientation
方法,该方法大概长这样
public static int getDisplayOrientation(Activity activity, int facing) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(facing, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
关闭相机
public void closeCamera() {
if (camera == null) {
return;
}
camera.stopPreview();
camera.release();
camera = null;
onCameraClosed();
}
切换相机
public void switchCamera() {
if (facing == CameraConstants.facing.BACK) {
facing = CameraConstants.facing.FRONT;
} else {
facing = CameraConstants.facing.BACK;
}
}
注意到,切换相机方法并没有真正的去切换相机,而是改变全局变量facing
的值,需要配合使用openCamera
方法后,进行切换相机的操作
接下来就是真正实现相机预览
四、TextureView
可以配合TextureView使用,进行相机相关操作
首先在xml中定义TextureView
<?xml version="1.0" encoding="utf-8"?>Activity中定义CameraManager
private final CameraManager cameraManager = new CameraManager();
打开相机
private void openCamera() {
if (textureView.isAvailable()) {
cameraManager.openCamera(TextureViewCameraActivity.this, textureView.getSurfaceTexture());
面试复习笔记:
这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《960页Android开发笔记》
《1307页Android开发面试宝典》
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
)]
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!