溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中使用攝像頭和相冊的示例

發(fā)布時間:2021-02-08 15:55:05 來源:億速云 閱讀:161 作者:小新 欄目:移動開發(fā)

這篇文章主要介紹Android中使用攝像頭和相冊的示例,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

很多 APP 應用都有用戶頭像功能,用戶既可以調用攝像頭馬上拍一張美美的自拍,也可以打開相冊選取一張心儀的照片作為頭像。

1 調用攝像頭

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <!--拍照按鈕-->
  <Button android:id="@+id/open_photo"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="拍照"
    />

  <!--照片展示-->
  <ImageView
    android:id="@+id/img"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    />

</LinearLayout>

活動類代碼:

public class MainActivity extends AppCompatActivity {

  private static final String TAG = "MainActivity";

  public static final int OPEN_PHOTO_REQUEST_CODE = 1;
  private Uri imgUrl = null;
  private ImageView imageView;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    //為按鈕添加【打開攝像頭】事件
    findViewById(R.id.open_photo).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        File file = new File(getExternalCacheDir(), "imageView.jpg");//存儲照片
        if (file.exists()) {
          file.delete();
        }
        try {
          file.createNewFile();
        } catch (IOException e) {
          e.printStackTrace();
        }


        if (Build.VERSION.SDK_INT >= 24) {//版本高于 7.0
          imgUrl = FileProvider.getUriForFile(MainActivity.this, "net.deniro.camera.fileProvider", file);
        } else {
          imgUrl = Uri.fromFile(file);
        }

        //打開攝像頭
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUrl);//指定圖片輸出地址
        startActivityForResult(intent, OPEN_PHOTO_REQUEST_CODE);
      }
    });

    //顯示拍攝的照片
    imageView = (ImageView) findViewById(R.id.img);


  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "requestCode: " + requestCode);
    Log.d(TAG, "imgUrl: " + imgUrl);
    switch (requestCode) {
      case OPEN_PHOTO_REQUEST_CODE:
        if (resultCode == RESULT_OK) {
          try {//解析圖片并顯示
            Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUrl));
            imageView.setImageBitmap(bitmap);
          } catch (FileNotFoundException e) {
            e.printStackTrace();
          }
        }
        break;
      default:
        break;
    }
  }
}

getExternalCacheDir() 可以獲取 SD 卡中專門用于存放當前應用緩存數(shù)據(jù)的位置。Android6.0+ 開始,讀取存放在 SD 卡中的任何其它目錄都被列為危險權限,因此需要設定運行時權限才可以操作,這里使用了與應用關聯(lián)的目錄,所以就可以跳過這一步。

getUriForFile() 方法接收三個參數(shù):Context對象、任意唯一的字符串與 File對象。從 android 7.0+ 系統(tǒng)開始,直接使用本地真實的路徑被認為是不安全的,會拋出一個 FileExposedException 異常,而 FileProvider 是一種特殊的內容提供器,它使用與內容提供器類似的機制對數(shù)據(jù)進行保護。

在 AndroidManifest.xml 中注冊剛才定義的內容提供器:

<provider
  android:name="android.support.v4.content.FileProvider"
  android:authorities="net.deniro.camera.fileProvider"
  android:exported="false"
  android:grantUriPermissions="true">
  <!--指定 Uri 的共享路徑-->
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_paths" />
</provider>

android:authorities 就是我們在 FileProvider.getUriForFile() 方法中傳入的第二個參數(shù)。

使用 <meta-data> 指定了 Uri 的共享路徑,在此引用了 xml 資源。

在 IDEA 中可以通過快捷鍵 ctrl + enter 直接在 xml 文件夾下創(chuàng)建文件:

Android中使用攝像頭和相冊的示例

快捷創(chuàng)建

Android中使用攝像頭和相冊的示例

默認為 xml 文件夾

file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
  <!--指定共享的 Uri -->
  <!--name:名稱(任意)-->
  <!--path:共享的路徑,空值表示共享整個 SD 卡-->
  <external-path name="img" path=""/>
</PreferenceScreen>

Android 4.4 之前,還需要設置訪問 SD 卡應用的關聯(lián)目錄權限:

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

拍照后效果:

Android中使用攝像頭和相冊的示例

2 從相冊中選取照片

直接從相冊中選取一張現(xiàn)有的照片比打開攝像頭拍一張照片更加常用,因此,一個好的 app,應該將這兩種方式都實現(xiàn)。

修改布局文件,加入【打開相冊】按鈕:

<!--打開相冊選取照片-->
<Button
  android:id="@+id/choose_photo"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="打開相冊"
  />

在活動類中加入打開相冊選取照片的處理邏輯:

/**
 * 打開相冊請求碼
 */
public static final int CHOOSE_PHOTO_REQUEST_CODE = 2;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  ...
  //打開相冊
  findViewById(R.id.choose_photo).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
            CHOOSE_PHOTO_REQUEST_CODE);
      } else {
        openAlbum();
      }
    }
});
/**
 * 打開相冊
 */
private void openAlbum() {
  Intent intent = new Intent("android.intent.action.GET_CONTENT");
  intent.setType("image/*");
  startActivityForResult(intent, CHOOSE_PHOTO_REQUEST_CODE);
}

/**
 * 請求 WRITE_EXTERNAL_STORAGE 權限
 *
 * 相冊中的照片一般是存放在 SD 卡上的,所以從 SD 卡中讀取照片需要申請權限
 *
 * WRITE_EXTERNAL_STORAGE 表示讀寫 SD 卡的能力權限
 * @param requestCode
 * @param permissions
 * @param grantResults
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  switch (requestCode) {
    case CHOOSE_PHOTO_REQUEST_CODE:
      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        openAlbum();
      } else {
        Toast.makeText(this, "被拒絕啦", Toast.LENGTH_SHORT).show();
      }
      break;
    default:
      break;
  }
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  Log.d(TAG, "requestCode: " + requestCode);
  Log.d(TAG, "imgUrl: " + imgUrl);
  switch (requestCode) {
    case OPEN_PHOTO_REQUEST_CODE:
      if (resultCode == RESULT_OK) {
        try {//解析圖片并顯示
          Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUrl));
          imageView.setImageBitmap(bitmap);
        } catch (FileNotFoundException e) {
          e.printStackTrace();
        }
      }
      break;
    case CHOOSE_PHOTO_REQUEST_CODE:
      if (Build.VERSION.SDK_INT >= 19) {//4.4 及以上系統(tǒng)
        handleFor4_4(data);
      } else {
        handleForBefore4_4(data);
      }
      break;
    default:
      break;
  }
}

/**
 * 處理相片
 * android 4.4-
 *
 * @param data
 */
private void handleForBefore4_4(Intent data) {
  display(getImagePath(data.getData(),null));
}

/**
 * 處理相片
 * android 4.4+
 *
 * @param data
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void handleFor4_4(Intent data) {
  String imagePath = null;
  Uri uri = data.getData();//需要解析
  if (DocumentsContract.isDocumentUri(this, uri)) {//是 Document 類型,使用 document id 來處理
    String documentId = DocumentsContract.getDocumentId(uri);
    String mediaDocumentAuthority = "com.android.providers.media.documents";
    String downloadDocumentAuthority = "com.android.providers.downloads.documents";
    if (mediaDocumentAuthority.equals(uri.getAuthority())) {//media 格式
      String id = documentId.split(":")[1];//數(shù)字格式的 ID
      String selection = MediaStore.Images.Media._ID + "=" + id;
      imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
    } else if (downloadDocumentAuthority.equals(uri.getAuthority())) {
      Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
      imagePath = getImagePath(contentUri, null);
    }
  } else if ("content".equalsIgnoreCase(uri.getScheme())) {//content 類型 uri
    imagePath = getImagePath(uri, null);
  } else if ("file".equalsIgnoreCase(uri.getScheme())) {//file 類型,則直接獲取路徑
    imagePath = uri.getPath();
  }
  display(imagePath);
}

/**
 * 顯示
 * @param path
 */
private void display(String path) {
  if(path==null){
    Toast.makeText(this, "無法獲取圖片", Toast.LENGTH_SHORT).show();
  }else{
    imageView.setImageBitmap(BitmapFactory.decodeFile(path));
  }


}

/**
 * 獲取圖片路徑
 *
 * @param uri
 * @param selection
 * @return
 */
private String getImagePath(Uri uri, String selection) {
  String path = null;
  Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
  if (cursor != null) {
    if (cursor.moveToFirst()) {
      path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
    }
    cursor.close();
  }
  return path;
}

這里請求了 WRITE_EXTERNAL_STORAGE 權限,以為相冊中的照片一般是存放在 SD 卡上的,所以從 SD 卡中讀取照片需要申請權限。WRITE_EXTERNAL_STORAGE 表示讀寫 SD 卡的能力權限。

為了兼容新老版本的手機(以 Android 4.4 為分水嶺),因為 Android 4.4+ 的版本返回的 Uri 需要解析才可以使用。

點擊【打開相冊】按鈕,會彈出讀取 SD 卡的權限申請:

Android中使用攝像頭和相冊的示例

選取照片后的效果:

Android中使用攝像頭和相冊的示例

以上是“Android中使用攝像頭和相冊的示例”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI