android camera2 拍照流程

正文

camera2 API 的加入是从AndroidV5.0(21)开始的,因此我们使用Camera2应该是在Android 5.0(含5.0)之后。同时,对于Android6.0我们需要有动态权限的管理。这两点应该是使用Camera2使用前的最基本认知。Android 5.0对拍照API进行了全新的设计,新增了全新设计的Camera v2 API,这些API不仅大幅提高了Android系统拍照的功能,还能支持RAW照片输出,甚至允许程序调整相机的对焦模式、曝光模式、快门等。下面不做过多介绍了,直接开撸了。

Camera2包架构示意图

我们先来看看 camera2包架构示意图(不用一下子理解,只需要有个整体印象): 
 
这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。

下面是 camera2包中的主要类:

 
CameraManager:摄像头管理器。这是一个全新的系统管理器,专门用于检测系统摄像头、打开系统摄像头。另外,调用CameraManager的getCameraCharacteristics(String cameraId)方法即可获取指定摄像头的相关特性。

CameraCharacteristics:摄像头特性。该对象通过CameraManager来获取,用于描述特定摄像头所支持的各种特性。类似与原来的CameraInfo 。

CameraDevice:代表系统摄像头。该类的功能类似于早期的Camera类。而每个 CameraDevice 自己会负责建立 CameraCaptureSession 以及建立 CaptureRequest。

CameraCaptureSession:这是一个非常重要的API,当程序需要预览、拍照时,都需要先通过该类的实例创建Session。而且不管预览还是拍照,也都是由该对象的方法进行控制的,其中控制预览的方法为setRepeatingRequest();控制拍照的方法为capture()。 
为了监听CameraCaptureSession的创建过程,以及监听CameraCaptureSession的拍照过程,Camera v2 API为CameraCaptureSession提供了StateCallback、CaptureCallback等内部类。

CameraRequest和CameraRequest.Builder:当程序调用setRepeatingRequest()方法进行预览时,或调用capture()方法进行拍照时,都需要传入CameraRequest参数。CameraRequest代表了一次捕获请求,用于描述捕获图片的各种参数设置,比如对焦模式、曝光模式……总之,程序需要对照片所做的各种控制,都通过CameraRequest参数进行设置。CameraRequest.Builder则负责生成CameraRequest对象。

相机预览与拍照流程

如果你看不太懂流程图,没关系,待会儿我们通过代码就可以更好的理解了。首先,Google官方推荐的Camera2控制拍照的步骤大致如下。

  • 1.用CameraManager的openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)方法打开指定摄像头。该方法的第一个参数代表要打开的摄像头ID;第二个参数用于监听摄像头的状态;第三个参数代表执行callback的Handler,如果程序希望直接在当前线程中执行callback,则可将handler参数设为null。

  • 2.当摄像头被打开之后会回调接口mStateCallback.onOpened,程序即可获取CameraDevice —— 即根据摄像头ID获取了指定摄像头设备,然后调用CameraDevice的createCaptureSession(List outputs, CameraCaptureSession. StateCallback callback,Handler handler)方法来创建CameraCaptureSession。该方法的第一个参数是一个List集合,封装了所有需要从该摄像头获取图片的Surface,第二个参数用于监听CameraCaptureSession的创建过程;第三个参数代表执行callback的Handler,如果程序希望直接在当前线程中执行callback,则可将handler参数设为null。

  • 3.不管预览还是拍照,程序都调用CameraDevice的createCaptureRequest(int templateType)方法创建CaptureRequest.Builder,该方法支持TEMPLATE_PREVIEW(预览)、TEMPLATE_RECORD(拍摄视频)、TEMPLATE_STILL_CAPTURE(拍照)等参数。
  • 4.通过第3步所调用方法返回的CaptureRequest.Builder设置拍照的各种参数,比如对焦模式、曝光模式等。
  • 5.调用CaptureRequest.Builder的build()方法即可得到CaptureRequest对象,接下来程序可通过CameraCaptureSession的setRepeatingRequest()方法开始预览,或调用capture()方法拍照。 
    相机的预览与拍照流程我们基本了解了。
  • 6预览时,是将mSurfaceHolder.getSurface()作为目标,使用setRepeatingRequest()方法, 
    显示拍照结果时,是将mImageReader.getSurface()作为目标,使用capture()方法。

然后这里还有一个大招:Google官方Camera2拍照的demo的地址:点击跳转github


首先是我们的layout代码

首先权限不能忘:

uses-permission android:name=”android.permission.CAMERA” / 
uses-feature android:name=”android.hardware.camera” / 
uses-feature android:name=”android.hardware.camera.autofocus” /

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextureViewandroid:id="@+id/texture"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"/><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/cancelButton"android:text="取消"android:visibility="invisible"/><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/captureButton"android:text="拍照"android:visibility="visible"/><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/saveButton"android:text="保存"android:visibility="invisible"/></LinearLayout>
</LinearLayout>

下面是我的代码

public class customCarmeraActivity extends AppCompatActivity {private static final int REQUEST_CAMERA_PERMISSION = 1;private static final int STATE_PREVIEW = 1;private static final int STATE_WAITING_PRECAPTURE = 2;private int mState = STATE_PREVIEW;private static final SparseIntArray ORIENTATIONS = new SparseIntArray();///为了使照片竖直显示static {ORIENTATIONS.append(Surface.ROTATION_0, 90);ORIENTATIONS.append(Surface.ROTATION_90, 0);ORIENTATIONS.append(Surface.ROTATION_180, 270);ORIENTATIONS.append(Surface.ROTATION_270, 180);}private CameraManager mCameraManagerm;private CameraDevice mCameraDevice;private String mCameraId;private HandlerThread mBackgroundThread;private Handler mBackgroundHandler;private TextureView mTextureView;private ImageReader mImageReader;private File mFile;private CaptureRequest.Builder mPreviewBuilder;private CaptureRequest mPreviewRequest;private CameraCaptureSession mCaptureSession;private Semaphore mCameraOpenCloseLock = new Semaphore(1);/*** Starts a background thread and its {@link Handler}.*/private void startBackgroundThread() {mBackgroundThread = new HandlerThread("CameraBackground");mBackgroundThread.start();mBackgroundHandler = new Handler(mBackgroundThread.getLooper());}/*** Stops the background thread and its {@link Handler}.*/private void stopBackgroundThread() {mBackgroundThread.quitSafely();try {mBackgroundThread.join();mBackgroundThread = null;mBackgroundHandler = null;} catch (InterruptedException e) {e.printStackTrace();}}/**** @TextureView.SurfaceTextureListener:public static interface* @onSurfaceTextureAvailable:Invoked when a TextureView's SurfaceTexture is ready for use.* @onSurfaceTextureSizeChanged:Invoked when the SurfaceTexture's buffers size changed.* @onSurfaceTextureDestroyed:Invoked when the specified SurfaceTexture is about to be destroyed.* @onSurfaceTextureUpdated:Invoked when the specified SurfaceTexture is updated through updateTexImage().*/private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {openCamera(width, height);}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {//configureTransform(width, height);}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {return true;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture texture) {}};/*** Shows a {@link Toast} on the UI thread.** @param text The message to show*/private void showToast(final String text) {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(customCarmeraActivity.this, text, Toast.LENGTH_SHORT).show();}});}/*** Capture a still picture. This method should be called when we get a response in* {@link #mCaptureCallback} from both {@link #lockFocus()}.*/private void captureStillPicture() {try {if (null == mCameraDevice) {return;}// This is the CaptureRequest.Builder that we use to take a picture.final CaptureRequest.Builder captureBuilder =mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);captureBuilder.addTarget(mImageReader.getSurface());//拍照时,是将mImageReader.getSurface()作为目标// Use the same AE and AF modes as the preview.captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);// Orientationint rotation = getWindowManager().getDefaultDisplay().getRotation();captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));CameraCaptureSession.CaptureCallback CaptureCallback= new CameraCaptureSession.CaptureCallback() {@Overridepublic void onCaptureCompleted(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {showToast("Saved: " + mFile);//Log.d("customCarmeraActivity", mFile.toString());unlockFocus();//恢复预览}};mCaptureSession.stopRepeating();mCaptureSession.abortCaptures();mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}private CameraCaptureSession.CaptureCallback mCaptureCallback =new CameraCaptureSession.CaptureCallback() {@Overridepublic void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,TotalCaptureResult result) {//Log.d("linc","mSessionCaptureCallback, onCaptureCompleted");mCaptureSession = session;checkState(result);}@Overridepublic void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,CaptureResult partialResult) {Log.d("linc","mSessionCaptureCallback,  onCaptureProgressed");mCaptureSession = session;checkState(partialResult);}private void checkState(CaptureResult result) {switch (mState) {case STATE_PREVIEW:// We have nothing to do when the camera preview is working normally.break;case STATE_WAITING_PRECAPTURE:Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);if (afState == null) {captureStillPicture();} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {// CONTROL_AE_STATE can be null on some devicesInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {//mState = STATE_PICTURE_TAKEN;captureStillPicture();} else {//runPrecaptureSequence();//视频拍摄}}break;}}};private void createCameraPreviewSession() {try {SurfaceTexture texture = mTextureView.getSurfaceTexture();//assert(texture != null);// We configure the size of default buffer to be the size of camera preview we want.texture.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());// This is the output Surface we need to start preview.Surface surface = new Surface(texture);mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);mPreviewBuilder.addTarget(surface);//预览时,是将Surface()作为目标mState = STATE_PREVIEW;mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {// The camera is already closedif (null == mCameraDevice) {return;}mCaptureSession = cameraCaptureSession;try {mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);mPreviewRequest = mPreviewBuilder.build();mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();Log.e("linc","set preview builder failed."+e.getMessage());}}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {Toast.makeText(customCarmeraActivity.this, "Camera configuration Failed", Toast.LENGTH_SHORT).show();}},mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}/**** @CameraDevice.StateCallback:public static abstract class* @onOpened:This method is called when the camera is opened.  We start camera preview here.* @onDisconnected:The method called when a camera device is no longer available for use.* @onError:The method called when a camera device has encountered a serious error.*/private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(CameraDevice cameraDevice) {mCameraOpenCloseLock.release();mCameraDevice = cameraDevice;createCameraPreviewSession();}@Overridepublic void onDisconnected(CameraDevice cameraDevice) {mCameraOpenCloseLock.release();cameraDevice.close();mCameraDevice = null;}@Overridepublic void onError(CameraDevice cameraDevice, int error) {mCameraOpenCloseLock.release();cameraDevice.close();mCameraDevice = null;}};private void getCameraId() {try {//Return the list of currently connected camera devices by identifier, including cameras that may be in use by other camera API clientsfor (String cameraId : mCameraManagerm.getCameraIdList()) {//Query the capabilities of a camera deviceCameraCharacteristics characteristics = mCameraManagerm.getCameraCharacteristics(cameraId);if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {continue;}mCameraId = cameraId;return;}} catch (CameraAccessException e) {e.printStackTrace();}}/*** Saves a JPEG {@link Image} into the specified {@link File}.*/private static class ImageSaver implements Runnable {/*** The JPEG image*/private final Image mImage;/*** The file we save the image into.*/private final File mFile;ImageSaver(Image image, File file) {mImage = image;mFile = file;}@Overridepublic void run() {ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();byte[] bytes = new byte[buffer.remaining()];buffer.get(bytes);FileOutputStream output = null;try {output = new FileOutputStream(mFile);output.write(bytes);} catch (IOException e) {e.printStackTrace();} finally {mImage.close();if (null != output) {try {output.close();} catch (IOException e) {e.printStackTrace();}}}}}private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {//showToast("onImageAvailable: " );mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));}};//TODO 执行完上面的请求权限后,系统会弹出提示框让用户选择是否允许改权限。选择的结果可以在回到接口中得知:@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {if (requestCode == REQUEST_CAMERA_PERMISSION) {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//用户允许改权限,0表示允许,-1表示拒绝 PERMISSION_GRANTED = 0, PERMISSION_DENIED = -1//permission was granted, yay! Do the contacts-related task you need to do.//这里进行授权被允许的处理} else {//permission denied, boo! Disable the functionality that depends on this permission.//这里进行权限被拒绝的处理}} else {super.onRequestPermissionsResult(requestCode, permissions, grantResults);}}/*** Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.*/private void openCamera(int width, int height) {//检查相机服务的访问权限if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {//Toast.makeText(this,"Lacking privileges to access camera service, please request permission first",Toast.LENGTH_SHORT).show();Log.e("customCarmeraActivity.openCamera","Lacking privileges to access camera service, please request permission first");ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);//API21后,向用户请求相机使用权限,然后执行onRequestPermissionsResult回调return;}getCameraId();//assert(mCameraId != null);mImageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG,/*maxImages*/7);mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);try {if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {throw new RuntimeException("Time out waiting to lock camera opening.");}mCameraManagerm.openCamera(mCameraId, mStateCallback, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();} catch (InterruptedException e) {throw new RuntimeException("Interrupted while trying to lock camera opening.", e);}}/*** Closes the current {@link CameraDevice}.*/private void closeCamera() {try {mCameraOpenCloseLock.acquire();if (null != mCaptureSession) {mCaptureSession.close();mCaptureSession = null;}if (null != mCameraDevice) {mCameraDevice.close();mCameraDevice = null;}if (null != mImageReader) {mImageReader.close();mImageReader = null;}} catch (InterruptedException e) {throw new RuntimeException("Interrupted while trying to lock camera closing.", e);} finally {mCameraOpenCloseLock.release();}}/*** Unlock the focus. This method should be called when still image capture sequence is* finished.*/private void unlockFocus() {try {// Reset the auto-focus triggermPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);/*       mCaptureSession.capture(mPreviewBuilder.build(), mCaptureCallback,mBackgroundHandler);*/// After this, the camera will go back to the normal state of preview.mState = STATE_PREVIEW;mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), mCaptureCallback, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}/*** Lock the focus as the first step for a still image capture.*/private void lockFocus() {try {// This is how to tell the camera to lock focus.mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CameraMetadata.CONTROL_AF_TRIGGER_START);// Tell #mCaptureCallback to wait for the lock.mState = STATE_WAITING_PRECAPTURE;mCaptureSession.capture(mPreviewBuilder.build(), mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.custom_carmera_layout);mCameraManagerm = (CameraManager)getSystemService(Context.CAMERA_SERVICE);mTextureView = (TextureView)findViewById(R.id.textureview);mFile = new File(getExternalFilesDir(null), "pic.jpg");Button tackPictureBtn = (Button)findViewById(R.id.takePictureButton);tackPictureBtn.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {//Log.i("linc", "take picture");lockFocus();}});}@Overrideprotected void onResume() {super.onResume();startBackgroundThread();if(mTextureView.isAvailable()) {openCamera(mTextureView.getWidth(), mTextureView.getHeight());} else{mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);}}@Overrideprotected void onPause() {super.onPause();closeCamera();stopBackgroundThread();}
}

https://blog.csdn.net/zhangzheng_1986/article/details/78710655?locationNum=9&fps=1

android camera(6)---camera2 拍照流程相关推荐

  1. Android手机拍照程序开发,android Camera开发-手机拍照流程

    android 拍照API流程 1. 在布局文件中添加一个 surfaceView (摄影平面) 2.根据 SurfaceView  获得 Holder (固定器) 3.给固定器设置 SurfaceH ...

  2. Android camera相机开发拍照功能

    在Android 5.0(SDK 21)中,Google使用Camera2替代了Camera接口.Camera2在接口和架构上做了巨大的变动,但是基于众所周知的原因,我们还必须基于 Android 4 ...

  3. Android Camera、Camera2详解

    前言 Android5.0之前使用android.hardware包下的Camera类进行拍照.录视频等功能.5.0以后,新增了android.hardware.camera2包,利用新的机制.新的类 ...

  4. Android Camera 打开预览流程分析(一)--打开camera的SDK流程

    Android系统应用场景中,Camera的使用场景变得越来越重要,在手机端不管是牌照美颜,还是拍小视频上传小视频平台.在其他领域,如车载,倒车视频,360全景影像也同样会用到Camera接口.那我们 ...

  5. Android Camera API/Camera2 API 相机预览及滤镜、贴纸等处理

    Android Lollipop 增加了Camera2 API,并将原来的Camera API标记为废弃了.相对原来的Camera API来说,Camera2是重新定义的相机 API,也重构了相机 A ...

  6. Android 10.0 Camera2 拍照功能默认选前摄像头

    1.概述 在10.0的系统产品开发中,对于app调用系统api来打开摄像头拍照的功能也是常有的功能,而拍照一般是默认打开后置摄像头拍照的,由于 客户的产品特殊要求,需要打开前置摄像头拍照功能,所以需要 ...

  7. Android如何使用Camera2拍照【简易快速上手篇】

    因为大部分的需求,并没有那么复杂,只需要简单的拍照功能,对于这种简单的需求,本文可以很好的满足.本文,是对Camera2做一个极简易的封装,以及去掉其它不重要的API,帮助你在几分钟内,使用Camer ...

  8. android camera噪点,拍照时总是有很多噪点怎么办?方法很简单但你还真不知道

    原标题:拍照时总是有很多噪点怎么办?方法很简单但你还真不知道 摄影时很多小伙伴对颗粒感格外偏爱,总觉得这种质感能让照片更耐看.可悲的是,有些人盲目沉迷这种效果,噪点让人像都成麻子脸了还洋洋自得. 颗粒 ...

  9. Android 10.0 Camera2 静音时拍照去掉快门声音

    1.概述 在10.0的系统产品开发中,对于Camera2相机的产品定制化中,发现在Camera2中发现一个问题 当媒体音量静音时,点击拍照还是有拍照声音,产品对这个不满意,所以要修改这个问题,所以针对 ...

最新文章

  1. 简谈-Python一些常用的爬虫技巧
  2. Linux Named 进程启动、停止脚本
  3. hashmap应用场景_Java初学者进阶系列:HashMap的容量与性能
  4. 关于ResultSet can not re-read row data for column 1 解决方法
  5. 使用Chronicle Wire将YAML连接到文件或网络
  6. 四种数据库特性对比(Redis/Mysql/SQLite/MongoDB)
  7. 从零基础入门Tensorflow2.0 ----七、33 数据padding,模型构建,训练
  8. Performing User-Managed Database-18.4、Restoring Datafiles and Archived Redo Logs
  9. 开源同步文件软件对比
  10. 好看的字体—方正粗倩
  11. 北京航天大学考研计算机科学与技术分数线,北京航空航天大学计算机科学与技术考研...
  12. 研发工程师L2_编程题
  13. android studio 显示view树_Android手势分发和嵌套滚动机制
  14. U大师U盘启动盘克隆制作工具
  15. 临床预测模型之综合判别改善指数IDI计算
  16. 为什么有的域名需要加WWW才能访问?
  17. python学习笔记之序列,内含列表和元组的常用方法
  18. 三年级下册计算机全册教案,小学三年级下册信息技术教案三篇
  19. 全球与中国沸石吸附剂市场深度研究分析报告
  20. sourceinsight使用技巧

热门文章

  1. char赋值字符串常量和数值的区别
  2. mac配置jenkins遇到的问题及解决办法
  3. python 第13天作业
  4. 洛谷 P3382 【模板】三分法
  5. 金明的预算方案(分组背包)
  6. js 返回上一页和刷新以及页面跳转
  7. Js 获取 本周、本月起始时间
  8. DROP TABLE ** CASCADE CONSTRAINTS PURGE删除表的时候级联删除从表外键
  9. Javascript进阶:数据类型
  10. springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)...