热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

简单说说Android中如何使用摄像头和相册

很多 APP 应用都有用户头像功能,用户既可以调用摄像头马上拍一张美美的自拍,也可以打开相册选取一张心仪的照片作为头像。 1 调用摄像头

很多 APP 应用都有用户头像功能,用户既可以调用摄像头马上拍一张美美的自拍,也可以打开相册选取一张心仪的照片作为头像。

1 调用摄像头

布局文件:

<&#63;xml version="1.0" encoding="utf-8"&#63;>


  
  

活动类代码:

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 卡中专门用于存放当前应用缓存数据的位置。Android6.0+ 开始,读取存放在 SD 卡中的任何其它目录都被列为危险权限,因此需要设定运行时权限才可以操作,这里使用了与应用关联的目录,所以就可以跳过这一步。

getUriForFile() 方法接收三个参数:Context对象、任意唯一的字符串与 File对象。从 android 7.0+ 系统开始,直接使用本地真实的路径被认为是不安全的,会抛出一个 FileExposedException 异常,而 FileProvider 是一种特殊的内容提供器,它使用与内容提供器类似的机制对数据进行保护。

在 AndroidManifest.xml 中注册刚才定义的内容提供器:


  
  

android:authorities 就是我们在 FileProvider.getUriForFile() 方法中传入的第二个参数。

使用 指定了 Uri 的共享路径,在此引用了 xml 资源。

在 IDEA 中可以通过快捷键 ctrl + enter 直接在 xml 文件夹下创建文件:

快捷创建

默认为 xml 文件夹

file_paths.xml:

<&#63;xml version="1.0" encoding="utf-8"&#63;>

  
  
  
  

Android 4.4 之前,还需要设置访问 SD 卡应用的关联目录权限:

 

拍照后效果:

2 从相册中选取照片

直接从相册中选取一张现有的照片比打开摄像头拍一张照片更加常用,因此,一个好的 app,应该将这两种方式都实现。

修改布局文件,加入【打开相册】按钮:


在活动类中加入打开相册选取照片的处理逻辑:

/**
 * 打开相册请求码
 */
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 及以上系统
        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];//数字格式的 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市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • 信息安全等级保护是指对国家秘密信息、法人和其他组织及公民的专有信息以及公开信息和存储、传输、处理这些信息的信息系统分等级实行安全保护,对信息系统中使用的信息安全产品实 ... [详细]
  • 无线认证设置故障排除方法及注意事项
    本文介绍了解决无线认证设置故障的方法和注意事项,包括检查无线路由器工作状态、关闭手机休眠状态下的网络设置、重启路由器、更改认证类型、恢复出厂设置和手机网络设置等。通过这些方法,可以解决无线认证设置可能出现的问题,确保无线网络正常连接和上网。同时,还提供了一些注意事项,以便用户在进行无线认证设置时能够正确操作。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文详细介绍了相机防抖的设置方法和使用技巧,包括索尼防抖设置、VR和Stabilizer档位的选择、机身菜单设置等。同时解释了相机防抖的原理,包括电子防抖和光学防抖的区别,以及它们对画质细节的影响。此外,还提到了一些运动相机的防抖方法,如大疆的Osmo Action的Rock Steady技术。通过本文,你将更好地理解相机防抖的重要性和使用技巧,提高拍摄体验。 ... [详细]
author-avatar
约醉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有