Android相机开发实战,Android程序员必看

这篇具有很好参考价值的文章主要介绍了Android相机开发实战,Android程序员必看。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

由于需求不同,所以选择的方案固然也不同,至于第二种调用系统相机,这里就不过多讲解了,使用Intent对象设置一个Action动作即可,跳转时使用startActivityForResult,然后在onActivityResult处理相关数据便可,关键代码:

intent.setAction(“android.media.action.STILL_IMAGE_CAMERA”);

至于使用,较常见的一般是应用中用户上传头像的时候调用,然后返回处理图像数据。

而第一种自定义相机的方式使用也十分普遍,但是要做好这个模块,相对来说还是有一定难度的,之前分享过一个Github上的开源相机的项目,项目由美国的一个团队开发,集 拍照、摄影、各种特效动画 等功能与一身,本人之前研究了下,发现功能比较全面也很强大,抠出来单独拍照那一个模块,我滴妈呀,真TM费劲!相机不管是预览还是拍摄图像都还是很清晰的,自己当时也写了一个,比较操蛋,只能怪自己对这一块的优化了解浅显吧!特别是预览的时候,聚焦完成后,焦点周边会出现很多白色的噪点,密密麻麻,特别严重,头疼的很。不过也总算解决了,灰常感谢USA的那个什么什么团队的开源相机程序。经过自己改造后的预览效果图:

下面看下这个项目的效果图,我也把地址甩底下,大伙感兴趣的自行Clone研究(或者闲的蛋疼也可以抽时间剥离开每一个模块学习,作为日后的知识储备),里面也用到了这个**Android中读取图片EXIF元数据之metadata-extractor的使用**。

GitHub:https://github.com/xplodwild/android_packages_apps_Focal

相机开发简介

==========

下面说说在Android中调用Camera来定义相机的最基本步骤:

  1. 打开相机 —— 调用Camera的open()方法。

  2. 获取拍照参数 —— 调用Camera的getParameters()方法,返回Camera.Parameters对象。

  3. 拍照参数设置 —— 调用Camera.Parameters对象。

  4. 拍照参数控制 —— 调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入。注:Android2.3.3之后不用设置。

  5. 预览取景 —— 调用Camera的startPreview()方法,在之前注意调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。

  6. 拍照 —— 调用Camera的takePicture()

  7. 停止预览 —— 调用Camera的stopPreview()方法

  8. 资源释放 —— Camera.release()

开启和关闭预览的联系如下:Camera ---- SurfaceHolder ------ SurfaceView

关于SurfaceHolder.Callback必须实现的3个方法:

surfaceCreated() 该方法在surfaceView被Create时调用

surfaceChanged() 该方法是当surfaceView发生改变后调用

surfaceDestroyed() 这个不用说了,销毁时调用

surfaceHolder通过addCallBack()方法将响应的接口绑定

注:必要Camera权限,例如:

关于Camera下的Parameters类,其中封装了我们需要的大部分功能,下面做个简单介绍:

  1. setPictureFormat() 方法用于设置相机照片的格式,其参数是一个字符型参数,位于PixelFormat类中,如:PixelFormat.JPEG。

  2. setSceneMode() 方法用于设置相机场景类型,其参是是一个字符型参数,位于Parameters类中,以SCENE_MODE_开头。

  3. setZoom() 方法用于设置相机焦距,其参数是一个整型的参数,该参数的范围是0到Camera.getParameters().getMaxZoom()。

  4. setPictureSize() 方法用于设置相机照片的大小,参数为整型。

  5. setWhiteBalance() 方法用于设置相机照片白平衡,其参数是一个字符型,位于Parameters类中,以WHITE_BALANCE开头。

  6. setJpegQuality() 方法用于设置相机照片的质量,其参数是一个整型参数,取值范围为1到100。

  7. setFlashMode() 方法用于设置闪光灯的类型,其参数是一个字符型参数,位于Parameters类中,以FLASH_MODE_开头。

  8. setColorEffect() 方法用于设置照片颜色特效的类型,其参数是一个字符型参数,位于Parameters类中,以EFFECT_开头。

本程序模块效果图及示例

===============

下面分享本篇Blog的示例相机模块,此功能模块并非上面开源项目中的剥离出来的,看下效果图咯:

         

         

效果看着还可以吧(不点赞也太不给面子了吧  - . - ),下面个出主界面的布局代码:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:id=“@+id/layout”

android:layout_width=“match_parent”

android:layout_height=“match_parent” >

<SurfaceView

android:id=“@+id/surfaceView”

android:layout_width=“match_parent”

android:layout_height=“match_parent” />

<RelativeLayout

android:layout_width=“match_parent”

android:layout_height=“match_parent” >

<org.gaochun.camera.CameraGrid

android:id=“@+id/camera_grid”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_alignParentTop=“true” />

<View

android:id=“@+id/focus_index”

android:layout_width=“40dp”

android:layout_height=“40dp”

android:background=“@drawable/camera_focus”

android:visibility=“invisible” />

<ImageView

android:id=“@+id/flash_view”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_alignParentLeft=“true”

android:onClick=“onClick”

android:padding=“15dp”

android:scaleType=“centerCrop”

android:src=“@drawable/camera_flash_off” />

<ImageView

android:id=“@+id/camera_flip_view”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_alignParentRight=“true”

android:onClick=“onClick”

android:padding=“15dp”

android:scaleType=“centerCrop”

android:src=“@drawable/camera_flip” />

<RelativeLayout

android:layout_width=“fill_parent”

android:layout_height=“70dp”

android:layout_alignParentBottom=“true”

android:background=“#a0000000”

android:padding=“5dp” >

<Button

android:id=“@+id/search”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_marginLeft=“30dp”

android:background=“@null”

android:drawablePadding=“3dp”

android:drawableTop=“@drawable/ic_search_selector”

android:onClick=“onClick”

android:text=“搜图”

android:textColor=“@drawable/row_selector_text” />

<ImageView

android:id=“@+id/action_button”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_centerInParent=“true”

android:clickable=“true”

android:onClick=“onClick”

android:src=“@drawable/btn_shutter_photo” />

<Button

android:id=“@+id/takephoto”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_alignParentRight=“true”

android:layout_marginRight=“30dp”

android:background=“@null”

android:drawablePadding=“3dp”

android:drawableTop=“@drawable/ic_takephoto_selector”

android:onClick=“onClick”

android:text=“拍照”

android:textColor=“@drawable/row_selector_text” />

下面是核心模块 CameraPreview 类:

public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback, Camera.AutoFocusCallback {

private SurfaceView mSurfaceView;

private SurfaceHolder mHolder;

private Size mPreviewSize;

private Size adapterSize;

//private List mSupportedPreviewSizes;

private Camera mCamera;

private boolean isSupportAutoFocus = false;

private Camera.Parameters parameters = null;

private Context mContext;

//private int mCurrentCameraId = 0;

private int screenWidth;

private int screenHeight;

CameraPreview(Context context, SurfaceView sv) {

super(context);

mContext = context;

mSurfaceView = sv;

mHolder = mSurfaceView.getHolder();

mHolder.addCallback(this);

mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

mHolder.setKeepScreenOn(true);

isSupportAutoFocus = context.getPackageManager().hasSystemFeature(

PackageManager.FEATURE_CAMERA_AUTOFOCUS);

DisplayMetrics dm = new DisplayMetrics();

((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);

screenWidth = dm.widthPixels;

screenHeight = dm.heightPixels;

}

public void setCamera(Camera camera) {

mCamera = camera;

initCamera();

}

public void initCamera() {

if (mCamera != null) {

Camera.Parameters params = mCamera.getParameters();

//mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();

requestLayout();

if (mPreviewSize == null) {

mPreviewSize = findBestPreviewResolution();

}

if (adapterSize == null) {

adapterSize = findBestPictureResolution();

}

if (adapterSize != null) {

params.setPictureSize(adapterSize.width, adapterSize.height);

}

if (mPreviewSize != null) {

params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

}

params.setPictureFormat(PixelFormat.JPEG);

List focusModes = params.getSupportedFocusModes();

if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {

// set the focus mode

params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

// set Camera parameters

mCamera.setParameters(params);

}

setDispaly(params, mCamera);

//setCameraDisplayOrientation((Activity) mContext, mCurrentCameraId, mCamera);

mCamera.setParameters(params);

}

}

//控制图像的正确显示方向

private void setDispaly(Camera.Parameters parameters, Camera camera) {

if (Build.VERSION.SDK_INT >= 8) {

setDisplayOrientation(camera, 90);

} else {

parameters.setRotation(90);

}

}

//实现的图像的正确显示

private void setDisplayOrientation(Camera camera, int i) {

Method downPolymorphic;

try {

downPolymorphic = camera.getClass().getMethod(“setDisplayOrientation”,

new Class[]{int.class});

if (downPolymorphic != null) {

downPolymorphic.invoke(camera, new Object[]{i});

}

} catch (Exception e) {

e.printStackTrace();

}

}

public static void setCameraDisplayOrientation(Activity activity,

int cameraId, android.hardware.Camera camera) {

android.hardware.Camera.CameraInfo info =

new android.hardware.Camera.CameraInfo();

android.hardware.Camera.getCameraInfo(cameraId, 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;

}

camera.setDisplayOrientation(result);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);

final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

setMeasuredDimension(width, height);

// if (mSupportedPreviewSizes != null) {

// mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);

// }

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

if (changed && getChildCount() > 0) {

final View child = getChildAt(0);

final int width = r - l;

final int height = b - t;

int previewWidth = width;

int previewHeight = height;

if (mPreviewSize != null) {

previewWidth = mPreviewSize.width;

previewHeight = mPreviewSize.height;

}

// Center the child SurfaceView within the parent.

if (width * previewHeight > height * previewWidth) {

final int scaledChildWidth = previewWidth * height / previewHeight;

child.layout((width - scaledChildWidth) / 2, 0,

(width + scaledChildWidth) / 2, height);

} else {

final int scaledChildHeight = previewHeight * width / previewWidth;

child.layout(0, (height - scaledChildHeight) / 2,

width, (height + scaledChildHeight) / 2);

}

}

}

public void surfaceCreated(SurfaceHolder holder) {

// The Surface has been created, acquire the camera and tell it where

// to draw.

try {

if (mCamera != null) {

mCamera.setPreviewDisplay(holder);

}

} catch (IOException e) {

if (null != mCamera) {

mCamera.release();

mCamera = null;

}

e.printStackTrace();

}

}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

if (holder.getSurface() == null) {

return;

}

if (mCamera != null) {

Camera.Parameters parameters = mCamera.getParameters();

parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

mCamera.setParameters(parameters);

try {

mCamera.setPreviewDisplay(holder);

} catch (IOException e) {

e.printStackTrace();

}

mCamera.startPreview();

reAutoFocus();

}

}

public void surfaceDestroyed(SurfaceHolder holder) {

// Surface will be destroyed when we return, so stop the preview.

if (mCamera != null) {

mCamera.stopPreview();

}

}

/**

  • 最小预览界面的分辨率

*/

private static final int MIN_PREVIEW_PIXELS = 480 * 320;

/**

  • 最大宽高比差

*/

private static final double MAX_ASPECT_DISTORTION = 0.15;

/**

  • 找出最适合的预览界面分辨率

  • @return

*/

private Camera.Size findBestPreviewResolution() {

Camera.Parameters cameraParameters = mCamera.getParameters();

Camera.Size defaultPreviewResolution = cameraParameters.getPreviewSize();

List<Camera.Size> rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();

if (rawSupportedSizes == null) {

return defaultPreviewResolution;

}

// 按照分辨率从大到小排序

List<Camera.Size> supportedPreviewResolutions = new ArrayList<Camera.Size>(rawSupportedSizes);

Collections.sort(supportedPreviewResolutions, new Comparator() {

@Override

public int compare(Camera.Size a, Camera.Size b) {

int aPixels = a.height * a.width;

int bPixels = b.height * b.width;

if (bPixels < aPixels) {

return -1;

}

if (bPixels > aPixels) {

return 1;

}

return 0;

}

});

StringBuilder previewResolutionSb = new StringBuilder();

for (Camera.Size supportedPreviewResolution : supportedPreviewResolutions) {

previewResolutionSb.append(supportedPreviewResolution.width).append(‘x’).append(supportedPreviewResolution.height)

.append(’ ');

}

// 移除不符合条件的分辨率

double screenAspectRatio = (double) screenWidth

/ screenHeight;

Iterator it = supportedPreviewResolutions.iterator();

while (it.hasNext()) {

Camera.Size supportedPreviewResolution = it.next();

int width = supportedPreviewResolution.width;

int height = supportedPreviewResolution.height;

// 移除低于下限的分辨率,尽可能取高分辨率

if (width * height < MIN_PREVIEW_PIXELS) {

it.remove();

continue;

}

// 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率

// 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height

// 因此这里要先交换然preview宽高比后在比较

boolean isCandidatePortrait = width > height;

int maybeFlippedWidth = isCandidatePortrait ? height : width;

int maybeFlippedHeight = isCandidatePortrait ? width : height;

double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;

double distortion = Math.abs(aspectRatio - screenAspectRatio);

if (distortion > MAX_ASPECT_DISTORTION) {

it.remove();

continue;

}

// 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回

if (maybeFlippedWidth == screenWidth

&& maybeFlippedHeight == screenHeight) {

return supportedPreviewResolution;

}

}

// 如果没有找到合适的,并且还有候选的像素,则设置其中最大比例的,对于配置比较低的机器不太合适

if (!supportedPreviewResolutions.isEmpty()) {

Camera.Size largestPreview = supportedPreviewResolutions.get(0);

return largestPreview;

}

// 没有找到合适的,就返回默认的

return defaultPreviewResolution;

}

private Camera.Size findBestPictureResolution() {

Camera.Parameters cameraParameters = mCamera.getParameters();

List<Camera.Size> supportedPicResolutions = cameraParameters.getSupportedPictureSizes(); // 至少会返回一个值

StringBuilder picResolutionSb = new StringBuilder();

for (Camera.Size supportedPicResolution : supportedPicResolutions) {

picResolutionSb.append(supportedPicResolution.width).append(‘x’)

.append(supportedPicResolution.height).append(" ");

}

Camera.Size defaultPictureResolution = cameraParameters.getPictureSize();

// 排序

List<Camera.Size> sortedSupportedPicResolutions = new ArrayList<Camera.Size>(

supportedPicResolutions);

Collections.sort(sortedSupportedPicResolutions, new Comparator<Camera.Size>() {

@Override

public int compare(Camera.Size a, Camera.Size b) {

int aPixels = a.height * a.width;

int bPixels = b.height * b.width;

if (bPixels < aPixels) {

return -1;

}

if (bPixels > aPixels) {

return 1;

}

return 0;

}

});

// 移除不符合条件的分辨率

double screenAspectRatio = screenWidth

/ (double) screenHeight;

Iterator<Camera.Size> it = sortedSupportedPicResolutions.iterator();

while (it.hasNext()) {

Camera.Size supportedPreviewResolution = it.next();

int width = supportedPreviewResolution.width;

int height = supportedPreviewResolution.height;

// 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率

// 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height

// 因此这里要先交换然后在比较宽高比

boolean isCandidatePortrait = width > height;

int maybeFlippedWidth = isCandidatePortrait ? height : width;

int maybeFlippedHeight = isCandidatePortrait ? width : height;

double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;

double distortion = Math.abs(aspectRatio - screenAspectRatio);

if (distortion > MAX_ASPECT_DISTORTION) {

it.remove();

continue;

}

}

// 如果没有找到合适的,并且还有候选的像素,对于照片,则取其中最大比例的,而不是选择与屏幕分辨率相同的

if (!sortedSupportedPicResolutions.isEmpty()) {

return sortedSupportedPicResolutions.get(0);

}

// 没有找到合适的,就返回默认的

return defaultPictureResolution;

}

private Size getOptimalPreviewSize(List sizes, int w, int h) {

final double ASPECT_TOLERANCE = 0.1;

double targetRatio = (double) w / h;

if (sizes == null)

return null;

Size optimalSize = null;

double minDiff = Double.MAX_VALUE;

int targetHeight = h;

// Try to find an size match aspect ratio and size

for (Size size : sizes) {

double ratio = (double) size.width / size.height;

if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)

continue;

if (Math.abs(size.height - targetHeight) < minDiff) {

optimalSize = size;

minDiff = Math.abs(size.height - targetHeight);

}

}

// Cannot find the one match the aspect ratio, ignore the requirement

if (optimalSize == null) {

minDiff = Double.MAX_VALUE;

for (Size size : sizes) {

if (Math.abs(size.height - targetHeight) < minDiff) {

optimalSize = size;

minDiff = Math.abs(size.height - targetHeight);

}

}

}

return optimalSize;

}

public void reAutoFocus() {

if (isSupportAutoFocus) {

mCamera.autoFocus(new Camera.AutoFocusCallback() {

@Override

public void onAutoFocus(boolean success, Camera camera) {

}

});

}

}

public List getResolutionList() {

return mCamera.getParameters().getSupportedPreviewSizes();

}

public Camera.Size getResolution() {

Camera.Parameters params = mCamera.getParameters();

Camera.Size s = params.getPreviewSize();

return s;

}

/*public void setCurrentCameraId(int current) {

mCurrentCameraId = current;

}*/

//定点对焦的代码

public void pointFocus(MotionEvent event) {

mCamera.cancelAutoFocus();

parameters = mCamera.getParameters();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {

//showPoint(x, y);

focusOnTouch(event);

}

mCamera.setParameters(parameters);

autoFocus();

}

//实现自动对焦

public void autoFocus() {

new Thread() {

@Override

public void run() {

try {

sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

if (mCamera == null) {

return;

}

mCamera.autoFocus(new Camera.AutoFocusCallback() {

@Override

public void onAutoFocus(boolean success, Camera camera) {

if (success) {

initCamera();//实现相机的参数初始化

}

}

});

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
Android相机开发实战,Android程序员必看,程序员,android,数码相机
Android相机开发实战,Android程序员必看,程序员,android,数码相机
Android相机开发实战,Android程序员必看,程序员,android,数码相机
Android相机开发实战,Android程序员必看,程序员,android,数码相机

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
Android相机开发实战,Android程序员必看,程序员,android,数码相机

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

Android相机开发实战,Android程序员必看,程序员,android,数码相机

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
Android相机开发实战,Android程序员必看,程序员,android,数码相机

  • 自行下载直达领取链接:点击这里前往GitHub

);

}

if (mCamera == null) {

return;

}

mCamera.autoFocus(new Camera.AutoFocusCallback() {

@Override

public void onAutoFocus(boolean success, Camera camera) {

if (success) {

initCamera();//实现相机的参数初始化

}

}

});

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-lSZtSmaI-1711372381342)]
[外链图片转存中…(img-JmvfSlVX-1711372381343)]
[外链图片转存中…(img-ZtHCLjWb-1711372381344)]
[外链图片转存中…(img-apOzgtih-1711372381344)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-sUe3HRxJ-1711372381344)]

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

[外链图片转存中…(img-LABtFmUY-1711372381345)]

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
[外链图片转存中…(img-Nf6QwByx-1711372381345)]文章来源地址https://www.toymoban.com/news/detail-852573.html

  • 自行下载直达领取链接:点击这里前往GitHub

到了这里,关于Android相机开发实战,Android程序员必看的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 互联网最新报告出炉!程序员必看系列!

    近期,CNNIC发布第50次《中国互联网络发展状况统计报告》,报告显示:截至2022年6月,①我国网民规模为10.51亿;②我国网民人均周上网29.5小时;③我国短视频用户规模达9.62亿,网络直播用户规模达7.16亿;④在线医疗用户规模达3.00亿。 自1997年起,CNNIC(中国互联网络信息中

    2024年02月12日
    浏览(43)
  • 《黑马程序员2023新版黑马程序员大数据入门到实战教程,大数据开发必会的Hadoop、Hive,云平台实战项目》学习笔记总目录

    本文是对《黑马程序员新版大数据入门到实战教程》所有知识点的笔记进行总结分类。 学习视频:黑马程序员新版大数据 学习时总结的学习笔记以及思维导图会在后续更新,请敬请期待。 前言:配置三台虚拟机,为集群做准备(该篇章请到原视频进行观看,不在文章内详细

    2024年02月03日
    浏览(70)
  • 【12章 Java IO流】程序员必看 IO流 详解

    ❤爱在开头 ❤博客主页: 努力的小鳴人 ❤系列专栏: JavaSE超详总结😋 ❤欢迎小伙伴们, 点赞👍关注🔎收藏🍔 一起学习! ❤如有错误的地方,还请小伙伴们指正!🌹 🔥系列传送门 : JavaSE超详总结😋 【附章5计算机字符编码】多种字符编码集的说明【热榜】 【11章J

    2023年04月16日
    浏览(36)
  • 一分钟看懂:前端和后端,哪个更简单?转行程序员必看!

    大家好,这里是程序员晚枫,专注于转行程序员的1对1咨询,小红薯也叫这个名。 想转行程序员的朋友,在选择方向的时候都会遇到一个问题: 哪个技术方向适合我?前端和后端哪个更简单? 今天咱们就来一起分析一下~ 很多网上的消息或者培训机构的广告会告诉你:前端比

    2024年02月07日
    浏览(43)
  • 黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动端

    1.1什么是网页? 1.2什么是HTML? 2.1常用的浏览器 2.2浏览器内核  3.1为啥需要Web标准? 3.2Web标准的构成 : 4.1基本语法概述: 4.2标签关系: 5.1HTML网页:   6.1VSCode常用快捷键: 第二篇:前端VSCode常用插件-快捷键-以及常用技巧-pink老师 - 哔哩哔哩 快速复制一行:shift+alt+下/上箭

    2024年04月08日
    浏览(93)
  • 【Android 逆向】程序员高危开发方向 ( 违法软件类型 | 赌博游戏 | 色情类应用 | 涉及金融类软件 | 爬虫类软件 | 区块链货币 | 甄别是否合法 )

    棋牌类 游戏开发 , 写这类游戏的程序员 很容易被抓 , 只要 涉及到了 充值 以及 提现 , 就是涉嫌赌博 ; 常见的 就是 麻将类游戏 , 纸牌类游戏 , 具体的地方麻将或扑克玩法 , 德州扑克 , 21 点 , 老虎机 等 类型的 游戏 ; 抽卡类的游戏 , 充值 然后 赌概率 , 比如原神这种 , 只充值

    2024年01月19日
    浏览(47)
  • Android程序员成长之路

    应该热爱学习Android知识 具备基本的自学能力和解决问题的能力 具备实践能力 Java(基本) C/C++(进阶) Kotlin(基本) Python(可选) 飞书学习路线图 学习路线图正在完善中... 当然读者也可以提出宝贵建议。 我将会按照 Android学习路线图 发布博客文章。 因本人才疏学浅,博客文章中难

    2024年02月09日
    浏览(45)
  • 低代码——面向程序员,帮助程序员敏捷开发

    低代码是一套可视化开发工具,它帮开发者把前后端基础功能写扎实,开发者只需要 通过填表配置或拖拽生成前端组件 的方式,即可完成后台管理系统的快速搭建。由于低代码仍需要 写少量 JS 代码 ,所以低代码开发平台主要面向程序员,帮助程序员敏捷开发。 本文使用

    2024年02月01日
    浏览(54)
  • 【黑马程序员】C++核心功能项目实战

    20240221 本教程主要利用C++来实现一个基于多态的职工管理系统 构成 普通员工 经理 老板 员工显示 需要显示职工编号、职工姓名、职工岗位以及职责 不同员工职责 责普通员工职责:完成经理交给的任务 经理职责:完成老板交给的任务,并下发任务给员工 老板职责:管理公司所有

    2024年02月22日
    浏览(46)
  • Python黑马程序员(Spark实战)笔记

     pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyspark 注意:字符串返回的是[\\\'a\\\',\\\'b\\\',\\\'c\\\',\\\'d\\\',\\\'e\\\',\\\'f\\\',\\\'g\\\']   字典返回的是[\\\'key1\\\',\\\'key2\\\']   读取hello.txt的内容: 注意: 如果没有添加上行代码程序会报出错误! Caused by: org.apache.spark.SparkException: Python worker failed to connect back.  解释器的位置

    2024年02月05日
    浏览(86)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包