zoukankan      html  css  js  c++  java
  • android ——调用摄像头拍照和相册

    先在布局文件中加入两个按钮和一个图片控件

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical">
     6 
     7     <Button
     8         android:id="@+id/take_photo"
     9         android:layout_width="match_parent"
    10         android:layout_height="wrap_content"
    11         android:text="拍照" />
    12 
    13     <Button
    14         android:id="@+id/choose_from_album"
    15         android:layout_width="match_parent"
    16         android:layout_height="wrap_content" 
    17         android:text="从相册里选择图片"/>
    18     
    19     <ImageView
    20         android:id="@+id/picture"
    21         android:layout_width="wrap_content"
    22         android:layout_height="wrap_content"
    23         android:layout_gravity="center_horizontal"/>
    24 
    25 </LinearLayout>

    然后先编写调用摄像头的代码:使用一个按钮来打开相机应用,然后在按钮的点击事件中调用摄像头

     1  takePhoto.setOnClickListener(new View.OnClickListener() {
     2             @Override
     3             public void onClick(View view) {
     4                 //创建File对象,用于存储拍照后的照片
     5                 File outputImage = new File(getExternalCacheDir(),"output_image.jpg");
     6                 try{
     7                     if(outputImage.exists()){
     8                         outputImage.delete();
     9                     }
    10                     outputImage.createNewFile();
    11                 }catch (IOException e){
    12                     e.printStackTrace();
    13                 }
    14                 
    15                 //将outputImage的路径由File对象转换成Uri对象
    16                 if(Build.VERSION.SDK_INT >= 24){
    17                     //如果是android7.0以上需要使用FileProvider.getUriForFile()这个方法
    18                     imageUri = FileProvider.getUriForFile(MainActivity.this,"xbt.exp14",outputImage);
    19                 }else {
    20                     //如果不是android7.0以上就直接调用Uri.fromFile()方法
    21                     imageUri = Uri.fromFile(outputImage);
    22                 }
    23 
    24                 //启动相机程序
    25                 Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
    26                 intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
    27                 startActivityForResult(intent, TAKE_PHOTO);
    28             }
    29         });

      先创建一个File对象用于存储摄像头拍下的照片,getExternalCacheDir()可以得到当前应用的关联缓存目录,具体就是/Android/data/(你的应用的名字)/cache

      然后要进行一个判断如果设备的系统版本低于Androi7.0,就直接调用Uri的fromFile()方法直接将File对象转换为Uri对象,如果是Androi7.0以上,因为系统对直接使用本地真实路径的Uri被认为是不安全的,所以用FileProvider这样一个特殊的内容提供器将封装过的Uri共享给外部,FileProvider.getUriForFile()有三个参数,第一个参数是Context()对象,第二个参数是一个任意唯一的字符串,第三个就是要转换的File对象。

      最后启动相机程序先是构建一个Intent对象,并将这个Intent的action指定为android.media.action.IMAGE_CAPTURE,再调用Intent的putExtra()方法指定图片的输出地址,再来使用startActivityForResult()启动响应这个intent。

      然后还要对内容提供器进行注册:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="xbt.exp14">
        ...
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="xbt.exp14"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths"/>
            </provider>
        </application>
    
    </manifest>

      android的属性值是固定的, android:authorities的属性值要与刚才FileProvider.getUriForFile()的第二个参数相同,<meta-data>用来指定Uri的共享路径,并引用了@xml/file_paths资源,不过这个资源需要自己创建。

      右击res目录→New→Directory,创建一个xml目录,然后右击这个xml目录→New→File,创建一个file_paths.xml文件,其中的内容如下:

    1 <?xml version="1.0" encoding="utf-8"?>
    2 <paths xmlns:android="http://schemas.android.com/apk/res/android">
    3     <external-path name="my_images" path="" />
    4 </paths>

      external-path就是用来指定Uri共享的,name 的属性值随便填,path的值表示共享的具体路径,空值就是整个SD卡。

      为了兼容Android4.4之前的系统,还需要声明权限:

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

       

      然后是使用系统相册的具体步骤大概是:

      1、验证是否拥有从sd卡读取照片的权限。

      2、如果没有读取的权限需要动态申请权限。

      3、打开系统相册。

      4、处理返回的Uri

      5、显示图片。

      所以按键choose_from_album的点击事件里首先验证是否拥有从sd卡读取照片的权限。

     1 chooseFromAlum.setOnClickListener(new View.OnClickListener() {
     2             @Override
     3             public void onClick(View view) {
     4                 //判断有没有使用相册的权限
     5                 if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
     6                     ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
     7                 }else{
     8                     Toast.makeText(MainActivity.this,"已经获取相册权限申请",Toast.LENGTH_SHORT).show();
     9                     openAlbum();
    10                 }
    11             }
    12         });
    13     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
    14         switch (requestCode){
    15             case 1 :
    16                 if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
    17                     openAlbum();;
    18                 }else{
    19                     Toast.makeText(MainActivity.this,"相册权限申请失败",Toast.LENGTH_SHORT).show();
    20                 }
    21                 break;
    22             default:
    23                 break;
    24         }
    25     }

      如果已经获取了权限使用openAlbum()方法打开相册。

    1     private void openAlbum(){
    2         Intent intent = new Intent("android.intent.action.GET_CONTENT");
    3         intent.setType("image/*");
    4         startActivityForResult(intent,CHOOSE_PHOTO);
    5     }

      在选择好图片后会返回到onActivityResult()方法中,这里先是验证系统的版本如果是Android4.4以上使用handleImageOnKitKat()方法处理返回的Uri,因为在Android系统从4.4开始选取相册中的图片就不再返回图片真实的Uri了,需要额外的解析。

     1 protected void onActivityResult(int requestCode, int resultCode,Intent data){
     2         switch (requestCode){
     3            ...
     4             case CHOOSE_PHOTO:
     5                 if(resultCode == RESULT_OK){
     6                     //判断手机的系统版本号
     7                     if(Build.VERSION.SDK_INT >= 19) {
     8                         // 4.4及以上系统使用这个方法处理图片
     9                         handleImageOnKitKat(data);
    10                     } else {
    11                         // 4.4以下系统使用这个方法处理图片
    12                         handleImageBeforeKitKat(data);
    13                     }
    14                 }
    15                 break;
    16             default:
    17                 break;
    18         }
    19     }

      handleImageOnKitKat()的代码是这样:

     1     private void handleImageOnKitKat (Intent data){
     2         String imagePath = null;
     3         Uri uri = data.getData();
     4         if(DocumentsContract.isDocumentUri(MainActivity.this,uri)){
     5             //如果是document类型的Uri,则通过document id 处理
     6             String docId = DocumentsContract.getDocumentId(uri);
     7             if("com.android.providers.media.documents".equals(uri.getAuthority())){
     8                 String id = docId.split(":")[1];
     9                 String selection  = MediaStore.Images.Media._ID + "=" + id;
    10                 imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
    11             }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
    12                 Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
    13                 imagePath = getImagePath(contentUri, null);
    14             }
    15         }else if("content".equalsIgnoreCase(uri.getScheme())){
    16             //如果是content类型的Uri,则使用普通的方式处理
    17             imagePath = getImagePath(uri, null);
    18         }else if("file".equalsIgnoreCase(uri.getScheme())){
    19             //如果是file类型的Uri,直接获取图片路径即可
    20             imagePath = uri.getPath();
    21         }
    22         displayImage(imagePath);
    23     }

      4.4以下的系统就不需要解析直接传入就好:

    1     private void handleImageBeforeKitKat (Intent data){
    2         Uri uri = data.getData();
    3         String imagePath = getImagePath(uri, null);
    4         displayImage(imagePath);
    5     }

      getImagePath()是一个通过Uri和selectio来获取图片的真实路径的方法:

     1     private String getImagePath(Uri uri, String selection){
     2         String path = null;
     3         Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
     4         if(cursor != null){
     5             if(cursor.moveToFirst()){
     6                 path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
     7             }
     8             cursor.close();
     9         }
    10         return path;
    11     }

      最后就是显示图片的方法:

    1     private void displayImage(String imagePath){
    2         if(imagePath != null){
    3             Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
    4             picture.setImageBitmap(bitmap);
    5         }else {
    6             Toast.makeText(MainActivity.this,"获取图片失败",Toast.LENGTH_SHORT).show();
    7         }
    8     }

      最后的最后就是整体的代码,

      1 public class MainActivity extends AppCompatActivity {
      2 
      3     public static final int TAKE_PHOTO = 1;
      4 
      5     public static final int CHOOSE_PHOTO = 2;
      6 
      7     private Uri imageUri;
      8 
      9     private ImageView picture;
     10 
     11     @Override
     12     protected void onCreate(Bundle savedInstanceState) {
     13         super.onCreate(savedInstanceState);
     14         setContentView(R.layout.activity_main);
     15 
     16         //获取按钮和图片的id
     17         Button takePhoto = (Button) findViewById(R.id.take_photo);
     18         Button chooseFromAlum = (Button)findViewById(R.id.choose_from_album);
     19         picture = (ImageView) findViewById(R.id.picture);
     20 
     21         //
     22         takePhoto.setOnClickListener(new View.OnClickListener() {
     23             @Override
     24             public void onClick(View view) {
     25                 //创建File对象,用于存储拍照后的照片
     26                 File outputImage = new File(getExternalCacheDir(),"output_image.jpg");
     27                 try{
     28                     if(outputImage.exists()){
     29                         outputImage.delete();
     30                     }
     31                     outputImage.createNewFile();
     32                 }catch (IOException e){
     33                     e.printStackTrace();
     34                 }
     35 
     36                 //将outputImage的路径由File对象转换成Uri对象
     37                 if(Build.VERSION.SDK_INT >= 24){
     38                     //如果是android7.0以上需要使用FileProvider.getUriForFile()这个方法
     39                     imageUri = FileProvider.getUriForFile(MainActivity.this,"xbt.exp14",outputImage);
     40                 }else {
     41                     //如果不是android7.0以上就直接调用Uri.fromFile()方法
     42                     imageUri = Uri.fromFile(outputImage);
     43                 }
     44 
     45                 //启动相机程序
     46                 Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
     47                 intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
     48                 startActivityForResult(intent, TAKE_PHOTO);
     49             }
     50         });
     51 
     52         chooseFromAlum.setOnClickListener(new View.OnClickListener() {
     53             @Override
     54             public void onClick(View view) {
     55                 //判断有没有使用相册的权限
     56                 if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
     57                     ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
     58                 }else{
     59                     Toast.makeText(MainActivity.this,"已经获取相册权限申请",Toast.LENGTH_SHORT).show();
     60                     openAlbum();
     61                 }
     62             }
     63         });
     64     }
     65 
     66     /*
     67     打开相册
     68      */
     69     private void openAlbum(){
     70         Intent intent = new Intent("android.intent.action.GET_CONTENT");
     71         intent.setType("image/*");
     72         startActivityForResult(intent,CHOOSE_PHOTO);
     73     }
     74 
     75     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
     76         switch (requestCode){
     77             case 1 :
     78                 if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
     79                     openAlbum();;
     80                 }else{
     81                     Toast.makeText(MainActivity.this,"相册权限申请失败",Toast.LENGTH_SHORT).show();
     82                 }
     83                 break;
     84             default:
     85                 break;
     86         }
     87     }
     88     protected void onActivityResult(int requestCode, int resultCode,Intent data){
     89         switch (requestCode){
     90             case TAKE_PHOTO:
     91                 if(resultCode == RESULT_OK){
     92                     try {
     93                         //将拍摄的照片显示出来
     94                         Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
     95                         picture.setImageBitmap(bitmap);
     96                         Toast.makeText(MainActivity.this,"图片已显示",Toast.LENGTH_SHORT).show();
     97                     } catch (FileNotFoundException e){
     98                         e.printStackTrace();
     99                     }
    100                 }
    101                 break;
    102             case CHOOSE_PHOTO:
    103                 if(resultCode == RESULT_OK){
    104                     //判断手机的系统版本号
    105                     if(Build.VERSION.SDK_INT >= 19) {
    106                         // 4.4及以上系统使用这个方法处理图片
    107                         handleImageOnKitKat(data);
    108                     } else {
    109                         // 4.4以下系统使用这个方法处理图片
    110                         handleImageBeforeKitKat(data);
    111                     }
    112                 }
    113                 break;
    114             default:
    115                 break;
    116         }
    117     }
    118 
    119     @TargetApi(19)
    120     private void handleImageOnKitKat (Intent data){
    121         String imagePath = null;
    122         Uri uri = data.getData();
    123         if(DocumentsContract.isDocumentUri(MainActivity.this,uri)){
    124             //如果是document类型的Uri,则通过document id 处理
    125             String docId = DocumentsContract.getDocumentId(uri);
    126             if("com.android.providers.media.documents".equals(uri.getAuthority())){
    127                 String id = docId.split(":")[1];
    128                 String selection  = MediaStore.Images.Media._ID + "=" + id;
    129                 imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
    130             }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
    131                 Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
    132                 imagePath = getImagePath(contentUri, null);
    133             }
    134         }else if("content".equalsIgnoreCase(uri.getScheme())){
    135             //如果是content类型的Uri,则使用普通的方式处理
    136             imagePath = getImagePath(uri, null);
    137         }else if("file".equalsIgnoreCase(uri.getScheme())){
    138             //如果是file类型的Uri,直接获取图片路径即可
    139             imagePath = uri.getPath();
    140         }
    141         displayImage(imagePath);
    142     }
    143 
    144     private void handleImageBeforeKitKat (Intent data){
    145         Uri uri = data.getData();
    146         String imagePath = getImagePath(uri, null);
    147         displayImage(imagePath);
    148 
    149     }
    150 
    151     private String getImagePath(Uri uri, String selection){
    152         String path = null;
    153         Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
    154         if(cursor != null){
    155             if(cursor.moveToFirst()){
    156                 path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
    157             }
    158             cursor.close();
    159         }
    160         return path;
    161     }
    162 
    163     private void displayImage(String imagePath){
    164         if(imagePath != null){
    165             Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
    166             picture.setImageBitmap(bitmap);
    167         }else {
    168             Toast.makeText(MainActivity.this,"获取图片失败",Toast.LENGTH_SHORT).show();
    169         }
    170     }
    171 }

      

  • 相关阅读:
    [单调栈] Jzoj P4260 最大子矩阵
    [前缀和] Jzoj P4259 矩形
    [欧拉回路][状压dp] Jzoj P3290 吃货JYY
    [组合数][枚举] Jzoj P3332 棋盘游戏
    [欧拉函数][dp][快速幂] Jzoj P1161 机器人M号
    [exgcd] Jzoj P1158 荒岛野人
    [带权并查集] Jzoj P1503 体育场
    [dfs][树的直径] Jzoj P1737 删边
    [差分][倍增lca][tarjan] Jzoj P3325 压力
    [dfs] Jzoj P1497 景点中心
  • 原文地址:https://www.cnblogs.com/xxbbtt/p/7449424.html
Copyright © 2011-2022 走看看