Camera相機是屬於硬件,每台設備的Camera硬件配置的參數都是不一樣的,Camera通常是用來拍照,掃描二維碼等等
AndroidManifest.xml配置Camera需要的權限:
<!-- 打開相機是很危險的行為,加入權限 --> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.autofocus"/> <!-- 保存圖片到sdcard外部存儲 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidManifest.xml配置Activity 橫屏顯示 + 全屏:
<!-- 設置橫屏顯示: android:screenOrientation="landscape" 設置無標題+全屏: android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" --> <activity android:name=".MyCameraActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
activity_camera.xml布局文件:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="對焦" android:layout_alignParentBottom="true" android:onClick="focus" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="拍照" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:onClick="takepicture" /> </RelativeLayout>
MyCameraActivity.java
package liudeli.my_media1; import android.app.Activity; import android.hardware.Camera; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class MyCameraActivity extends Activity { private final String TAG = MySurfaceViewActivity.class.getSimpleName(); /** * 操作的是SurfaceHolder,所以定義全局變量 */ private SurfaceHolder surfaceHolder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); // 獲取在布局文件中定義的SurfaceView SurfaceView surfaceView = findViewById(R.id.surface_view); // 不能直接操作SurfaceView,需要通過SurfaceView拿到SurfaceHolder surfaceHolder = surfaceView.getHolder(); // 使用SurfaceHolder設置屏幕高亮,注意:所有的View都可以設置 設置屏幕高亮 surfaceHolder.setKeepScreenOn(true); // 使用SurfaceHolder設置把畫面或緩存 直接顯示出來 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); /** * 由於要觀察SurfaceView生命周期,所以需要設置監聽 * 此監聽不一樣,是addCallback * */ surfaceHolder.addCallback(callback); } /** * 定義相機對象 */ private Camera camera; /** * 定義SurfaceView監聽回調 */ private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() { /** * SurfaceView被創建了 * @param holder */ @Override public void surfaceCreated(SurfaceHolder holder) { /** * 只有在SurfaceView生命周期方法-->SurfaceView被創建后在打開相機 * 以前我在 onResume 之前去打開相機,結果報錯了,所以只有在這里打開相機,才是安全🔐 */ // Camera要選擇hardware.Camera,因為Camera屬於硬件hardware // Camera.open(1); // 這了傳入的值,可以指定為:前置攝像頭/后置攝像頭 camera = Camera.open(0); /** * 設置Camera與SurfaceHolder關聯,Camera的數據讓SurfaceView顯示 */ try { camera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); Log.e(TAG, "相機設置預覽失敗"); } /** * 開始顯示 */ camera.startPreview(); } /** * SurfaceView發生改變了 * @param holder * @param format * @param width * @param height */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 以后做具體業務功能的時候,才會用到改變的值來處理 // ...... } /** * SurfaceView被銷毀了 * @param holder */ @Override public void surfaceDestroyed(SurfaceHolder holder) { /** * SurfaceView被銷毀后,一定要釋放硬件資源,Camera是硬件 */ camera.stopPreview(); // (一定要有,不然只release也可能出問題) camera.release(); camera = null; System.gc(); } }; /** * 拍照 */ public void takepicture(View view) { if (null != camera) { /** * 參數一:相機的快門,咔嚓,這里用不到 * 參數二:相機原始的數據 * 參數三:相機處理后的數據 */ camera.takePicture(null, null, pictureCallback); } } /** * 相機處理后的數據回調 */ private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() { /** * 拍照完成,可以拿到數據了 * @param data 數據 * @param camera */ @Override public void onPictureTaken(byte[] data, Camera camera) { // 寫在指定目錄 sdcard 中去 File file = new File(Environment.getExternalStorageDirectory(), "pictureCallback.jpg"); try { // 字節文件輸出流,把byte[]數據寫入到文件里面去 OutputStream os = new FileOutputStream(file); os.write(data); // 關閉字節文件輸出流 os.close(); } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "保存失敗"); Toast.makeText(MyCameraActivity.this, "照片保存失敗", Toast.LENGTH_SHORT).show(); } } }; /** * 對焦 */ public void focus(View view) { // 對焦都是硬件設備來完成的 camera.autoFocus(null); } /** * 當Activity被銷毀的時候,一定要移除監聽 */ @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, ">>>> onDestroy()"); if (null != callback) surfaceHolder.removeCallback(callback); } }