編輯:Android開發實例
前言
在開發Android應用的時候,如果需要調用攝像頭獲取拍攝的照片,除了通過Intent調用系統現有相機應用拍攝照片之外,還可以通過直接調用Camera硬件去去獲取攝像頭拍攝的照片。本文將講解如何在Android應用中通過Camera拍攝照片,這個對開發相機類應用尤為重要,同樣最後也將以一個簡單的Demo演示。
本文的主要內容:
Camera
Camera是Android攝像頭硬件的相機類,位於硬件包"android.hardware.Camera"下。它主要用於攝像頭捕獲圖片、啟動/停止預覽圖片、拍照、獲取視頻幀等,它是設備本地的服務,負責管理設備上的攝像頭硬件。
Camera既然用於管理設備上的攝像頭硬件,那麼它也為開發人員提供了相應的方法,並且這些方法大部分都是native的,用C++在底層實現,下面簡單介紹一下Camera的一些方法:
上面已經介紹了Camera的常用方法,下面根據這些方法詳細講解Android下使用Camera開發拍照應用最基本的過程:
以上介紹的步驟都是最基本的過程,是必不可少的。Camera沒有提供公開的構造函數,只能通過open()方法獲取,並且必須設置一個預覽類SurfaceHolder,如果不設置的話,將無法使用Camera。在使用完成Camera之後,必須使用release()釋放Camera資源。
驗證設備是否配備攝像頭硬件
因為Android的開源,所以其支持的設備多而雜,在使用Camera的時候,最好驗證一下當前運行的設備上是否配備了攝像頭硬件。這裡需要用到一個PackageManager,它用於檢測應用安裝設備的各種信息,可以通過Context.getPackageManager()方法獲取。可以通過PackageManager.hasSystemFeature(String name)方法檢測設備是否支持攝像頭操作,它傳遞的是一個String類型的參數,被PackageManager定義為了常量,返回一個Boolean數據,驗證是否檢測通過,對於Camera而言,可以檢測如下信息:
一般而言,檢測FEATURE_CAMERA即可:
- /** 檢測設備是否存在Camera硬件 */
- private boolean checkCameraHardware(Context context) {
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_CAMERA)) {
- // 存在
- return true;
- } else {
- // 不存在
- return false;
- }
- }
Camera捕獲畫面的預覽
Camera的預覽,需要放到一個SurfaceView中,出於安全的考慮,在設計Android的時候就規定,如果需要調用Camera,必須為其制定顯示在屏幕上的SurfaceView預覽,否則將無法使用Camera。關於SurfaceView和SurfaceHolder的內容,在之前的博客中已經詳細講解,這裡不再贅述,不清楚的朋友可以看看之前的:http://www.fengfly.com/plus/view-214102-1.html。
下面我們直接使用一個類去繼承SurfaceView當做Camera的預覽類:
- package cn.bgxt.camerapicturedemo;
- import java.io.IOException;
- import android.content.Context;
- import android.hardware.Camera;
- import android.util.Log;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- /**
- * 定義一個預覽類
- */
- public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
- private static final String TAG = "main";
- private SurfaceHolder mHolder;
- private Camera mCamera;
- public CameraPreview(Context context, Camera camera) {
- super(context);
- mCamera = camera;
- // 通過SurfaceView獲得SurfaceHolder
- mHolder = getHolder();
- // 為SurfaceHolder指定回調
- mHolder.addCallback(this);
- // 設置Surface不維護自己的緩沖區,而是等待屏幕的渲染引擎將內容推送到界面 在Android3.0之後棄用
- mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- }
- public void surfaceCreated(SurfaceHolder holder) {
- // 當Surface被創建之後,開始Camera的預覽
- try {
- mCamera.setPreviewDisplay(holder);
- mCamera.startPreview();
- } catch (IOException e) {
- Log.d(TAG, "預覽失敗");
- }
- }
- public void surfaceDestroyed(SurfaceHolder holder) {
- }
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- // Surface發生改變的時候將被調用,第一次顯示到界面的時候也會被調用
- if (mHolder.getSurface() == null){
- // 如果Surface為空,不繼續操作
- return;
- }
- // 停止Camera的預覽
- try {
- mCamera.stopPreview();
- } catch (Exception e){
- Log.d(TAG, "當Surface改變後,停止預覽出錯");
- }
- // 在預覽前可以指定Camera的各項參數
- // 重新開始預覽
- try {
- mCamera.setPreviewDisplay(mHolder);
- mCamera.startPreview();
- } catch (Exception e){
- Log.d(TAG, "預覽Camera出錯");
- }
- }
- }
使用Camera拍照
當指定了Camera的預覽類,並開始預覽之後,就可以通過takePicture()方法進行拍照了,下面是它的完整簽名:
上面已經定義好了SurfaceView,它是一個Camera的預覽類,下面直接通過一個示例演示Camera是如何進行拍照的,備注都比較詳細,這裡不再贅述了。
public final void taskPicture(Camera.ShuffterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback postview,Camera.PictureCallback jpeg)
它將以異步的方式從Camera中獲取圖像,具有多個回調類作為參數,並且都可以為null,下面分別介紹這些參數的意義:
雖然raw、postview、jpeg都是Camera.PictureCallback回調,但是一般我們只需要獲取jpeg,其他傳null即可,Camera.PictureCallback裡需要實現一個方法onPictureTaken(byte[] data,Camera camera),data及為圖像數據。值得注意的是,一般taskPicture()方法拍照完成之後,SurfaceView都會停留在拍照的瞬間,需要重新調用startPreview()才會繼續預覽。
如果直接使用taskPicture()進行拍照的話,Camera是不會進行自動對焦的,這裡需要使用Camera.autoFocus()方法進行對焦,它傳遞一個Camera.AutoFocusCallback參數,用於自動對焦完成後回調,一般會在它對焦完成在進行taskPicture()拍照。
使用Camera拍照的Demo
上面已經介紹了使用Camera的基本步驟以及涉及的內容,這裡通過一個簡單的Demo演示一下,使用上面附上代碼的預覽類進行Camera預覽。代碼中注釋比較完整,這裡不再贅述。
布局代碼:activity_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <FrameLayout
- android:id="@+id/camera_preview"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- />
- <Button
- android:id="@+id/button_capture"
- android:text="拍照"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- />
- </LinearLayout>
實現代碼:MainActivity.java
- package cn.bgxt.camerapicturedemo;
- import java.io.File;
- import java.io.FileOutputStream;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.FrameLayout;
- import android.app.Activity;
- import android.content.Context;
- import android.content.pm.PackageManager;
- import android.hardware.Camera;
- import android.hardware.Camera.AutoFocusCallback;
- import android.hardware.Camera.PictureCallback;
- public class MainActivity extends Activity {
- protected static final String TAG = "main";
- private Camera mCamera;
- private CameraPreview mPreview;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mCamera = getCameraInstance();
- // 創建預覽類,並與Camera關聯,最後添加到界面布局中
- mPreview = new CameraPreview(this, mCamera);
- FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
- preview.addView(mPreview);
- Button captureButton = (Button) findViewById(R.id.button_capture);
- captureButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 在捕獲圖片前進行自動對焦
- mCamera.autoFocus(new AutoFocusCallback() {
- @Override
- public void onAutoFocus(boolean success, Camera camera) {
- // 從Camera捕獲圖片
- mCamera.takePicture(null, null, mPicture);
- }
- });
- }
- });
- }
- /** 檢測設備是否存在Camera硬件 */
- private boolean checkCameraHardware(Context context) {
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_CAMERA)) {
- // 存在
- return true;
- } else {
- // 不存在
- return false;
- }
- }
- /** 打開一個Camera */
- public static Camera getCameraInstance() {
- Camera c = null;
- try {
- c = Camera.open();
- } catch (Exception e) {
- Log.d(TAG, "打開Camera失敗失敗");
- }
- return c;
- }
- private PictureCallback mPicture = new PictureCallback() {
- @Override
- public void onPictureTaken(byte[] data, Camera camera) {
- // 獲取Jpeg圖片,並保存在sd卡上
- File pictureFile = new File("/sdcard/" + System.currentTimeMillis()
- + ".jpg");
- try {
- FileOutputStream fos = new FileOutputStream(pictureFile);
- fos.write(data);
- fos.close();
- } catch (Exception e) {
- Log.d(TAG, "保存圖片失敗");
- }
- }
- };
- @Override
- protected void onDestroy() {
- // 回收Camera資源
- if(mCamera!=null){
- mCamera.stopPreview();
- mCamera.release();
- mCamera=null;
- }
- super.onDestroy();
- }
- }
效果展示:
Camera的回調監聽
上面介紹Camera拍照的時候介紹了兩個回調,Camera還提供了一些其他的回調的事件監聽方法,這裡簡單介紹幾個常用的:
Camera的參數設置
Camera作為一個攝像頭硬件的調用類,還為我們提供了詳細的設置攝像頭各項參數的方法,比如閃光燈的模式、自動對焦的模式等。步驟是使用Camera.getParameters()方法獲取到Camera.Parameters對象,在其中設置好攝像頭的各項參數後,再通過Camera.setParameters()方法寫入到Camera對象中即可。這個設置必須在使用startPreview()之前完成。關於Camera參數的設置,比較細致,不在本篇博客的內容之中,以後有機會再詳細介紹。
源碼下載
當我們第一次下載QQ並且打開的時候,會有一個新手引導,引導是幾張圖片,再加上一些文字說明,向右滑動,直到結束,今天一大早起來研究了一下關於此種效果的實現之View
JSON代表JavaScript對象符號。它是一個獨立的數據交換格式,是XML的最佳替代品。本章介紹了如何解析JSON文件,並從中提取所需的信息。Android提供了四個
1、xml代碼:代碼如下:<?xml version=1.0 encoding=utf-8?> <LinearLayout xmln
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩