1.获取权限
获取相机和读写权限:
1 2
| <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
2.创建layout
一个简单的layout用来实时显示内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<SurfaceView android:id="@+id/sfv_preview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" />
<Button android:id="@+id/btn_take" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="照相" />
</LinearLayout>
|
3.创建java代码调用相机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
| package com.example.pageview.careme;
import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.hardware.Camera; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.example.pageview.R;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date;
public class camera extends Activity {
public static final String CAMERA_PATH = "path"; public static final String CAMERA_IMG = "img";
private SurfaceView mSurfaceView; private Button mTakePhoto; private Camera mCamera = null;
private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { startPreview(); }
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
@Override public void surfaceDestroyed(SurfaceHolder holder) { stopPreview(); } };
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera);
getPermission();
bindViews(); }
private void getPermission() { if (Build.VERSION.SDK_INT > 22) { if (checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100); } else { Log.i("Camera", "已经获取了权限"); } } else { Log.i("Camera", "这个说明系统版本在6.0之下,不需要动态获取权限。"); } }
private void bindViews() { mSurfaceView = (SurfaceView) findViewById(R.id.sfv_preview); mTakePhoto = (Button) findViewById(R.id.btn_take); mSurfaceView.getHolder().addCallback(mCallback);
mTakePhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCamera.takePicture(null, null, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { String path = savePhoto(data); if (!TextUtils.isEmpty(path)) { Intent it = new Intent(camera.this, PreviewActivity.class); it.putExtra(CAMERA_PATH, path); startActivity(it); } else { Toast.makeText(getApplicationContext(), "拍照失败", Toast.LENGTH_SHORT).show(); } } }); } }); }
private String savePhoto(byte[] bytes) { try { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); Log.d("Camera", "Storage directory: " + storageDir.getAbsolutePath());
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
Log.d("Camera", "Image file path: " + image.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(image); fos.write(bytes); fos.flush(); fos.close(); return image.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); Log.e("Camera", "Failed to save photo", e); return ""; } }
private void startPreview() { mCamera = Camera.open(); try { mCamera.setPreviewDisplay(mSurfaceView.getHolder()); mCamera.setDisplayOrientation(90); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } }
private void stopPreview() { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } }
|
4. 实时显示图片
创建一个java代码,直接打开刚刚拍照的图片,可以减少layout的创建和调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.example.pageview.careme;
import android.net.Uri; import android.os.Bundle; import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.File;
public class PreviewActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ImageView img = new ImageView(this); String path = getIntent().getStringExtra("path"); if(path != null){ img.setImageURI(Uri.fromFile(new File(path))); } setContentView(img); } }
|
5. 查看图片
图片保存在/Android/data/com.包名/files/Pictures/JPEG_事件.jpg
6. 代码优化
以上调用的是camera1,有更加优化性能的camera2版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
| package com.example.pageview.careme;
import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.hardware.Camera; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.example.pageview.R;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date;
public class CameraActivity extends Activity {
public static final String CAMERA_PATH = "path"; public static final String CAMERA_IMG = "img";
private SurfaceView mSurfaceView; private Button mTakePhoto; private Camera mCamera = null;
private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { startPreview(); }
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
@Override public void surfaceDestroyed(SurfaceHolder holder) { stopPreview(); } };
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera);
checkPermissions(); bindViews(); }
private void checkPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100); } else { Log.i("Camera", "权限已获得"); } } else { Log.i("Camera", "不需要动态请求权限"); } }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 100) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.i("Camera", "权限已授予"); } else { Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show(); } } }
private void bindViews() { mSurfaceView = findViewById(R.id.sfv_preview); mTakePhoto = findViewById(R.id.btn_take); mSurfaceView.getHolder().addCallback(mCallback);
mTakePhoto.setOnClickListener(v -> { mCamera.takePicture(null, null, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { String path = savePhoto(data); if (!TextUtils.isEmpty(path)) { Intent it = new Intent(CameraActivity.this, PreviewActivity.class); it.putExtra(CAMERA_PATH, path); startActivity(it); } else { Toast.makeText(getApplicationContext(), "拍照失败", Toast.LENGTH_SHORT).show(); } } }); }); }
private String savePhoto(byte[] bytes) { File image = null; try { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); Log.d("Camera", "存储目录: " + storageDir.getAbsolutePath());
image = File.createTempFile(imageFileName, ".jpg", storageDir); Log.d("Camera", "图片路径: " + image.getAbsolutePath());
try (FileOutputStream fos = new FileOutputStream(image)) { fos.write(bytes); fos.flush(); } return image.getAbsolutePath(); } catch (IOException e) { Log.e("Camera", "保存照片失败", e); return ""; } }
private void startPreview() { mCamera = Camera.open(); try { mCamera.setPreviewDisplay(mSurfaceView.getHolder()); mCamera.setDisplayOrientation(90); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } }
private void stopPreview() { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } }
|
7. 版本差异
Camera1 和 Camera2 是 Android 中用于访问相机的两种 API,具有一些显著的区别。以下是它们之间的主要差异:
1. API 设计与架构
- Camera1:
- 设计较早,结构较简单,主要用于基本的相机功能。
- 提供的功能有限,难以处理复杂的相机操作。
- 主要依赖于
Camera 类及其回调接口。
- Camera2:
- 设计更现代,提供了更灵活和全面的功能。
- 支持更复杂的相机功能,如手动对焦、曝光控制和高分辨率图像等。
- 采用了更模块化的设计,使用
CameraManager、CameraCaptureSession 和 CameraDevice 等类进行操作。
2. 功能支持
- Camera1:
- 不支持高级特性,如 RAW 图像捕获、慢动作视频、深度相机等。
- 对于图像的控制和处理较为有限。
- Camera2:
- 支持高级特性,如 RAW 图像、运动跟踪、面部识别和高动态范围(HDR)图像。
- 允许更细粒度的控制,开发者可以实现自定义的相机行为。
3. 异步处理
- Camera1:
- 主要使用同步方法进行相机操作,容易导致 UI 阻塞。
- 处理图像数据时的灵活性较低。
- Camera2:
- 支持异步处理,通过回调机制来处理相机操作,提供更好的用户体验。
- 支持设置多个捕获请求,允许并行处理。
4. 支持的设备和版本
- Camera1:
- 在 Android 5.0(API 级别 21)之前广泛使用,适用于大多数设备。
- 随着 Android 版本更新,其使用逐渐减少。
- Camera2:
- 从 Android 5.0(API 级别 21)开始引入,逐渐取代
Camera1。
- 需要设备支持
Camera2 API 才能使用其高级功能。
5. 使用复杂性
- Camera1:
- 使用简单,适合快速实现基本相机功能。
- 适合初学者,但功能受限。
- Camera2:
- 使用复杂,学习曲线较陡峭,但功能强大。
- 适合需要实现复杂相机应用的开发者。
总结
- 如果只需要基本的相机功能,
Camera1 可能更容易实现。
- 如果需要更高级的功能和更好的控制,建议使用
Camera2 API。它提供了更灵活的接口和更强大的功能,适合现代应用开发。