【Android Developers Training】 48. 轻松拍摄

系统 2370 0

注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接: http://developer.android.com/training/camera/photobasics.html


这节课将展示如何使用已经存在的相机应用拍摄相机。

假设你现在在实现一个基于人群的气象服务,它构建一个全球的气象地图,通过将运行了你的应用色设备所拍摄的天空照片拼接起来来实现这个气象地图。整合照片只是你的应用的一小部分。你希望通过最简单地方式拍摄照片,而不是需要重新构造一个相机。大多数Android设备其实已经至少有了一个相机应用。在这节课中,你将学习如何利用它来为您拍摄一个照片。


一). 请求相机权限

如果你的应用中一个重要的函数会拍摄照片,同时限制只有那些拥有相机的设备可以在Google Play上下载。为了声明你的应用依赖于一个相机,在你的清单文件中放置一个 <uses-feature> 标签:

      
        <
      
      
        manifest 
      
      
        ... 
      
      
        >
      
      
        <
      
      
        uses-feature 
      
      
        android:name
      
      
        ="android.hardware.camera"
      
      
        

                  android:required
      
      
        ="true"
      
      
        />
      
      
        

    ...


      
      
        </
      
      
        manifest
      
      
        >
      
    

如果你的应用使用,但并不依赖一个相机来执行功能,那么将“ android:required ”设置为“ false ”。这样的话,那么Google Play将会允许没有相机的设备下载你的应用。那么接下来就是你的责任在运行时如果调用了需要用相机的函数时, 通过调用 hasSystemFeature(PackageManager.FEATURE_CAMERA) 检查是否可以获取相机。如果相机无法获取,那么你就应该禁止你的相关功能特性。


二). 使用相机应用拍摄照片

在Android中向其它应用分发意图是通过激活一个描述你的意图的 Intent 。这一过程分为三步: Intent 自身,调用外部 Activity ,当焦点回到你的activity中处理图像数据的一些代码。

下面的代码是构造一个intent来获取一张照片。

      
        static
      
      
        final
      
      
        int
      
       REQUEST_IMAGE_CAPTURE = 1
      
        ;




      
      
        private
      
      
        void
      
      
         dispatchTakePictureIntent() {

    Intent takePictureIntent 
      
      = 
      
        new
      
      
         Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    
      
      
        if
      
       (takePictureIntent.resolveActivity(getPackageManager()) != 
      
        null
      
      
        ) {

        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);

    }

}
      
    

注意这里 startActivityForResult() 方法被一个前提所保护,那就是通过调用 resolveActivity() ,返回第一个可以处理该intent的组件。执行这个检查时很重要的因为如果你调用了 startActivityForResult() 并使用一个没有一个应用可以处理的 intent ,你的应用将会崩溃。所以只要结果不是 null,那么使用这个intent是安全的。


三). 获取缩略图

如果简单地获取照片不是你的应用的终极目标,那么你可能希望从相机应用收回图像并做一些事情。

Android相机应用在 onActivityResult() 中传递的 Intent 内,将照片编码并作为一个小的位图( Bitmap )在“ extras ”,在键“ data ”下。下面的代码将会获得一个图像并在 ImageView 中显示。

      
        @Override


      
      
        protected
      
      
        void
      
       onActivityResult(
      
        int
      
       requestCode, 
      
        int
      
      
         resultCode, Intent data) {

    
      
      
        if
      
       (requestCode == REQUEST_IMAGE_CAPTURE && resultCode ==
      
         RESULT_OK) {

        Bundle extras 
      
      =
      
         data.getExtras();

        Bitmap imageBitmap 
      
      = (Bitmap) extras.get("data"
      
        );

        mImageView.setImageBitmap(imageBitmap);

    }

}
      
    

Note:

这个来自“ data ”的缩略图用作图标hi非常好的,但是如果用作更大的图片就不行了。处理全尺寸的图片需要更多操作。


四). 保存全尺寸照片

如果你提供了一个存储文件的地方,Android相机应用就可以存储全尺寸的照片。你必须提供一个完整的文件名来指定相机应用应该把照片保存在哪里。

一般来说,任何用户通过相机拍摄的照片都应该存储在设备的公共外部存储区域,这样他们就能被所有应用访问。一个合适的共享照片存储目录可以通过带有 DIRECTORY_PICTURES 参数的 getExternalStoragePublicDirectory() 函数获得。因为由该方法提供的目录是被所有应用所共享的,在目录内读或写分别要 READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE 的权限声明。写权限隐含了读权限,所以如果你需要写入外部目录,那么你只需要声明一个权限:

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

    ...


      
      
        </
      
      
        manifest
      
      
        >
      
    

然而,如果你希望保持这些照片是你应用私有的,那么你可以使用由 getExternalFilesDir() 提供的目录。在Android 4.3或更低版本的系统中,写入该目录也需要 WRITE_EXTERNAL_STORAGE 权限。从Android 4.4以后,这个权限就不在需要了。因为这个目录对其他应用来说是访问不到的,所以你可以通过使用 maxSdkVersion 字段来表明该权限声明只对低版本有效:

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

                     android:maxSdkVersion
      
      
        ="18"
      
      
        />
      
      
        

    ...


      
      
        </
      
      
        manifest
      
      
        >
      
    

Note:

你存储在由 getExternalFilesDir() 所提供的目录内的文件,将会在用户删除你的应用时一起被删除。

一旦你决定了文件存储的目录,你需要创建一个不容易重名的文件名。你可能也希望在成员变量中存储路径名,以备今后使用。这里是一个方法的例子,它通过时间戳为一个新照片返回一个唯一的文件名:

      
        String mCurrentPhotoPath;




      
      
        private
      
       File createImageFile() 
      
        throws
      
      
         IOException {

    
      
      
        //
      
      
         Create an image file name
      
      

    String timeStamp = 
      
        new
      
       SimpleDateFormat("yyyyMMdd_HHmmss").format(
      
        new
      
      
         Date());

    String imageFileName 
      
      = "JPEG_" + timeStamp + "_"
      
        ;

    File storageDir 
      
      =
      
         Environment.getExternalStoragePublicDirectory(

            Environment.DIRECTORY_PICTURES);

    File image 
      
      =
      
         File.createTempFile(

        imageFileName,  
      
      
        /*
      
      
         prefix 
      
      
        */
      
      

        ".jpg",         
      
        /*
      
      
         suffix 
      
      
        */
      
      
        

        storageDir      
      
      
        /*
      
      
         directory 
      
      
        */
      
      
        

    );



    
      
      
        //
      
      
         Save a file: path for use with ACTION_VIEW intents
      
      

    mCurrentPhotoPath = "file:" +
      
         image.getAbsolutePath();

    
      
      
        return
      
      
         image;

}
      
    

通过这种方法为照片创建了文件,现在你可以像下面这样创建并激活 Intent

      
        static
      
      
        final
      
       in REQUEST_TAKE_PHOTO = 1
      
        ;




      
      
        private
      
      
        void
      
      
         dispatchTakePictureIntent() {

    Intent takePictureIntent 
      
      = 
      
        new
      
      
         Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    
      
      
        //
      
      
         Ensure that there's a camera activity to handle the intent
      
      
        if
      
       (takePictureIntent.resolveActivity(getPackageManager()) != 
      
        null
      
      
        ) {

        
      
      
        //
      
      
         Create the File where the photo should go
      
      

        File photoFile = 
      
        null
      
      
        ;

        
      
      
        try
      
      
         {

            photoFile 
      
      =
      
         createImageFile();

        } 
      
      
        catch
      
      
         (IOException ex) {

            
      
      
        //
      
      
         Error occurred while creating the File
      
      
                    ...

        }

        
      
      
        //
      
      
         Continue only if the File was successfully created
      
      
        if
      
       (photoFile != 
      
        null
      
      
        ) {

            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,

                    Uri.fromFile(photoFile));

            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);

        }

    }

}
      
    

五). 将照片添加至图库:

当你通过一个intent创建了一个照片,你应该知道照片放置在哪里,因为你指定了它需要存储在哪里。对其他任何应用来说,可能最简单的让你照片可访问的方法就是让它可被系统的媒体提供程序( Media Provider )可被访问。

Note:

如果你把文件存储在了由 getExternalFilesDir() 提供的路径,那么此时媒体扫描器

下面的方法证明了如何激活系统的媒体扫描器将你的照片添加至照片提供程序的数据库,使它对Android图库应用和其它应用来说是可以访问的。

      
        private
      
      
        void
      
      
         galleryAddPic() {

    Intent mediaScanIntent 
      
      = 
      
        new
      
      
         Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

    File f 
      
      = 
      
        new
      
      
         File(mCurrentPhotoPath);

    Uri contentUri 
      
      =
      
         Uri.fromFile(f);

    mediaScanIntent.setData(contentUri);

    
      
      
        this
      
      
        .sendBroadcast(mediaScanIntent);

}
      
    

六). 解码缩放图像

管理多个全尺寸图像对于有限的存储空间来说是很复杂的。如果你发现你的应用在显示了几幅图片后就用尽了存储,那么你可以通过将JPEG延展到一个记忆数组里面,它将图片缩放至目标View的尺寸,这样可以大幅减小使用的动态堆内存。下面的代码展示了这一技术:

      
        private
      
      
        void
      
      
         setPic() {

    
      
      
        //
      
      
         Get the dimensions of the View
      
      
        int
      
       targetW =
      
         mImageView.getWidth();

    
      
      
        int
      
       targetH =
      
         mImageView.getHeight();



    
      
      
        //
      
      
         Get the dimensions of the bitmap
      
      

    BitmapFactory.Options bmOptions = 
      
        new
      
      
         BitmapFactory.Options();

    bmOptions.inJustDecodeBounds 
      
      = 
      
        true
      
      
        ;

    BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);

    
      
      
        int
      
       photoW =
      
         bmOptions.outWidth;

    
      
      
        int
      
       photoH =
      
         bmOptions.outHeight;



    
      
      
        //
      
      
         Determine how much to scale down the image
      
      
        int
      
       scaleFactor = Math.min(photoW/targetW, photoH/
      
        targetH);



    
      
      
        //
      
      
         Decode the image file into a Bitmap sized to fill the View
      
      

    bmOptions.inJustDecodeBounds = 
      
        false
      
      
        ;

    bmOptions.inSampleSize 
      
      =
      
         scaleFactor;

    bmOptions.inPurgeable 
      
      = 
      
        true
      
      
        ;



    Bitmap bitmap 
      
      =
      
         BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);

    mImageView.setImageBitmap(bitmap);

}
      
    

【Android Developers Training】 48. 轻松拍摄照片


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论