Android拍照并添加进相册

最近有个小需求,在移动设备(iOS / Android)中应用调用拍照并把所拍照片存入相册。我原本以为这是一个很简单的事情,不就拍个照然后把照片丢进相册?心想最多100行代码即可解决问题,谁知还是踩中坑。且听我一一分解。

必备权限

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

添加入 AndroidManifest.xml 中

执行拍照

File destDir = new File(m_ImageRootPath);
if (!destDir.exists())
{
      destDir.mkdirs();
}

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(m_ImageRootPath , m_ImageName)));
startActivityForResult(intent, 100);

代码中 m_ImageRootPath 为照片所存目录,m_ImageName为照片名。注意,若拍照不止一张 则照片名字最好每次不一样,否则你打开相册有可能每次都只能看到一张照片。

拍照回调

//-------------------------------------------------------------------------
/**
 * Activity 回调
 */
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if (requestCode == 100)
    {

        if (0 == resultCode)
        {
            // 拍照失败
        }
        else
        {
            // 拍照成功
            __SaveImage2Media();
        }

        finish();
    }

    super.onActivityResult(requestCode, resultCode, data);
}
//-------------------------------------------------------------------------

拍照后的回调,你在网上找到N个版本都差不多的 所以不解释了。重点看下面保存照片到相册

保存照片到相册

private void __SaveImage2Media()
{
    try
    {

        __FixMediaDir();

        File file = new File(m_ImageRootPath + m_ImageMiddlePath + m_ImageName);
        Uri uri = Uri.fromFile(file);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri), null, options);
        options.inSampleSize = 4;
        options.inJustDecodeBounds = false;
        Bitmap map = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri), null, options);

        String strCapturedImage = MediaStore.Images.Media.insertImage(getContentResolver(), map, null, null);
        if (null == strCapturedImage || strCapturedImage.isEmpty())
        {
            long dateTaken = System.currentTimeMillis();
            String strFilePath = m_ImageRootPath + m_ImageName;
            ContentValues values = new ContentValues(7);
            values.put(MediaStore.Images.Media.TITLE, m_ImageName);
            values.put(MediaStore.Images.Media.DISPLAY_NAME, m_ImageName);
            values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken);
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
            values.put(MediaStore.Images.Media.DATA, strFilePath);
            getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        }
        else
        {
            Uri capturedImage = Uri.parse(strCapturedImage);
            MediaScannerConnection.scanFile(this, new String[] { __GetFilePathByContentResolver(this, capturedImage) }, null, null);
        }


    }
    catch (Exception e)
    {
        // 保存出错
    }

}
//-------------------------------------------------------------------------
private void __FixMediaDir()
{
    File sdcard = Environment.getExternalStorageDirectory();
    if (sdcard != null)
    {
        File mediaDir = new File(sdcard, "DCIM/Camera");

        if (!mediaDir.exists())
        {
            mediaDir.mkdirs();
        }
    }
}
//-------------------------------------------------------------------------
private String __GetFilePathByContentResolver(Context context, Uri uri)
{
    if (null == uri)
    {
        return null;
    }

    Cursor c = context.getContentResolver().query(uri, null, null, null, null);
    String filePath = null;
    if (null == c)
    {
        throw new IllegalArgumentException(
                "Error:" + uri + " is Null");
    }
    try
    {
        if ((c.getCount() != 1) || !c.moveToFirst())
        {

        }
        else
        {
            filePath = c.getString(
                    c.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA));
        }
    }
    finally
    {
        c.close();
    }
    return filePath;
}
  1. 函数 __FixMediaDir 创建默认的相册目录,有些设备这个目录是没有的或者很多时候被误删也正常。
  2. 函数 __GetFilePathByContentResolver 通过 uri 取图片全路径,用来刷新相册
  3. 函数 __SaveImage2Media 保存所拍照片到相册

一号坑

在 __SaveImage2Media 函数中刷新相册使用此句:

MediaScannerConnection.scanFile(
this, new String[]{__GetFilePathByContentResolver(this,capturedImage)}, null, null);

这句代码的作用是只刷新单个照片,就是我们刚刚拍照所得的那一张。在android老版本中是直接刷新SD卡中全部的,但是那种方法在高版本的android设备中会秒崩。

二号坑

在 __SaveImage2Media 函数中保存图片的部分:

// 第一种
String strCapturedImage =     MediaStore.Images.Media.insertImage(getContentResolver(), map, null, null);
if (null == strCapturedImage || strCapturedImage.isEmpty())
{
   // 第二种
    long dateTaken = System.currentTimeMillis();
    String strFilePath = m_ImageRootPath + m_ImageName;
    ContentValues values = new ContentValues(7);
    values.put(MediaStore.Images.Media.TITLE, m_ImageName);
    values.put(MediaStore.Images.Media.DISPLAY_NAME, m_ImageName);
    values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    values.put(MediaStore.Images.Media.DATA, strFilePath);
    getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
else
{
    Uri capturedImage = Uri.parse(strCapturedImage);
    MediaScannerConnection.scanFile(this, new String[]{__GetFilePathByContentResolver(this,capturedImage)}, null, null);
}

有两种保存图片的方式,第一种是大家普遍使用的,但是经过我测试发现 第一种方式在某些设备(例如三星SM-T810平板电脑)中会永远返回null。所以当返回的字符串为null的时候执行第二种方式。第一种方式直接把照片写入相册 第二种方式直接把照片的信息索引添加入相册。如此便可在大多数设备上成功让照片在相册中显示(虽然并不都是真实保存到相册)

-EOF-

1 评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注