首先新建一个CameraAlbumTest项目。然后修改activity_main.xml中的代码,如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:orientation="vertical" 8 tools:context=".MainActivity"> 9 10 <Button 11 android:id="@+id/take_photo" 12 android:layout_width="match_parent" 13 android:layout_height="wrap_content" 14 android:text="Take Phote" 15 /> 16 17 18 <ImageView 19 android:id="@+id/picture" 20 android:layout_width="wrap_content" 21 android:layout_height="wrap_content" 22 android:layout_gravity="center_horizontal" 23 /> 24 25 </LinearLayout>
定义完布局后,定义mainactivity
1 package com.example.cameraalbumtest; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 import androidx.core.content.FileProvider; 5 6 import android.content.Intent; 7 import android.graphics.Bitmap; 8 import android.graphics.BitmapFactory; 9 import android.net.Uri; 10 import android.os.Build; 11 import android.os.Bundle; 12 import android.provider.MediaStore; 13 import android.view.View; 14 import android.widget.Button; 15 import android.widget.ImageView; 16 17 import java.io.File; 18 import java.io.FileNotFoundException; 19 import java.io.IOException; 20 21 public class MainActivity extends AppCompatActivity { 22 23 public static final int TAKE_PHOTO=1; 24 25 private ImageView picture; 26 27 private Uri imageUri; 28 29 @Override 30 protected void onCreate(Bundle savedInstanceState) { 31 super.onCreate(savedInstanceState); 32 setContentView(R.layout.activity_main); 33 34 //获取实例 35 Button takePhoto=(Button) findViewById(R.id.take_photo); 36 picture =(ImageView) findViewById(R.id.picture); 37 38 takePhoto.setOnClickListener(new View.OnClickListener() { 39 @Override 40 public void onClick(View v) { 41 //创建file对象,用于存储拍照后的图片 42 File outputImage=new File(getExternalCacheDir(),"output_image.jpg");//把图片进行命名 43 //调用getExternalCacheDir()可以得到手机SD卡的应用关联缓存目录 44 //所谓的应用关联缓存目录,就是指SD卡中专门用于存放当前应用缓存数据的位置 45 //具体的路径是/sdcard/Android/data/<package name>/cache 46 47 //因为从Android 6.0系统开始,读写SD卡被列为了危险权限, 48 // 如果将图片存放在SD卡的任何其他目录,都要进行运行时权限处理才行,而使用应用关联目录则可以跳过这一步。 49 try { 50 if (outputImage.exists()) {//如果已经存在了图片,则删掉, 51 outputImage.delete(); 52 } 53 outputImage.createNewFile();//将图片放入 54 }catch (IOException e){ 55 e.printStackTrace(); 56 } 57 58 //获取Uri对象 59 //这个Uri对象标识着output_image.jpg这张图片的本地真实路径。 60 if (Build.VERSION.SDK_INT >= 24) { 61 //调用FileProvider的getUriForFile() 方法将File 对象转换成一个封装过的Uri对象 62 imageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider", outputImage); 63 //FileProvider则是一种特殊的内容提供器,它使用了和内容提供器类似的机制来对数据进行保护, 64 // 可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。 65 //第一个参数要求传入Context 对象 66 //第二个参数可以是任意唯一的字符串 (需要在AndroidManifest.xml中声明) 67 //第三个参数则是我们刚刚创建的File 对象 68 69 } else {//若系统的版本低于Android7.0,则调用下面的方法将File对象转换为Uri对象 70 imageUri = Uri.fromFile(outputImage); 71 } 72 73 //启动相机程序 74 Intent intent= new Intent("android.media.action.IMAGE_CAPTURE"); 75 intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);//指定图片的输出地址 76 startActivityForResult(intent,TAKE_PHOTO);//调用startActivityForResult() 来启动活动。 77 } 78 }); 79 80 } 81 82 //使用startActivityForResult() 来启动活动的, 83 // 因此拍完照后会有结果返回到onActivityResult() 方法中。 84 @Override 85 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 86 super.onActivityResult(requestCode, resultCode, data); 87 switch (requestCode) { 88 case TAKE_PHOTO: 89 if (resultCode == RESULT_OK) {//如果拍照成功 90 try { 91 // 将拍摄的照片显示出来 92 //可以调用BitmapFactory的decodeStream() 方法将output_image.jpg这张照片解析成Bitmap 对象 93 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); 94 picture.setImageBitmap(bitmap);//将Bitmap对象,设置到ImageView中显示出来。 95 } catch (FileNotFoundException e) { 96 e.printStackTrace(); 97 } 98 } 99 break; 100 default: 101 break; 102 } 103 } 104 }
由于采用到了内容提供器(FileProvider),那么我们自然要在AndroidManifest.xml中对内容提供器进行注册了,如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.cameraalbumtest"> 4 5 <application 6 android:allowBackup="true" 7 android:icon="@mipmap/ic_launcher" 8 android:label="@string/app_name" 9 android:roundIcon="@mipmap/ic_launcher_round" 10 android:supportsRtl="true" 11 android:theme="@style/AppTheme"> 12 13 <provider 14 android:name="android.support.v4.content.FileProvider" 15 android:authorities="com.example.cameraalbumtest.fileprovider" 16 android:exported="false" 17 android:grantUriPermissions="true"> 18 <meta-data 19 android:name="android.support.FILE_PROVIDER_PATHS" 20 android:resource="@xml/file_paths" /> 21 </provider> 22 23 <activity android:name=".MainActivity"> 24 <intent-filter> 25 <action android:name="android.intent.action.MAIN" /> 26 27 <category android:name="android.intent.category.LAUNCHER" /> 28 </intent-filter> 29 </activity> 30 </application> 31 32 </manifest>
其中,android:name 属性的值是固定的,android:authorities 属性的值必须要和刚才FileProvider.getUriForFile() 方法中的第二个参数一致。另外,这里还在<provider> 标签的内部使用<meta-data> 来指定Uri 的共享路径,并引用了一个@xml/file_paths 资源。当然,这个资源现在还是不存在的,下面我们就来创建它。
右击res 目录→New→Directory,创建一个xml目录,接着右击xml目录→New→File,创建一个file_paths.xml文件。然后修改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卡进行共享。
同时声明一下访问SD卡的权限
1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
运行会发现报错。感觉第一行代码里面的程序的版本还是有点低哎。比如这里,必须填路径,但是里面就说空都可以。修改AndroidManifest.xml中的fileprovider后有
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.cameraalbumtest"> 4 5 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 6 7 <application 8 android:allowBackup="true" 9 android:icon="@mipmap/ic_launcher" 10 android:label="@string/app_name" 11 android:roundIcon="@mipmap/ic_launcher_round" 12 android:supportsRtl="true" 13 android:theme="@style/AppTheme"> 14 15 <activity android:name=".MainActivity"> 16 <intent-filter> 17 <action android:name="android.intent.action.MAIN" /> 18 19 <category android:name="android.intent.category.LAUNCHER" /> 20 </intent-filter> 21 </activity> 22 23 <provider 24 android:name="androidx.core.content.FileProvider" 25 android:authorities="***.fileProvider" 26 android:exported="false" 27 android:grantUriPermissions="true" 28 xmlns:tools="http://schemas.android.com/tools" 29 tools:replace="android:authorities"> 30 <meta-data 31 android:name="android.support.FILE_PROVIDER_PATHS" 32 android:resource="@xml/file_paths" /> 33 </provider> 34 35 36 </application> 37 38 </manifest>
再修改
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>
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.cameraalbumtest"> 4 5 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 6 7 <application 8 android:allowBackup="true" 9 android:icon="@mipmap/ic_launcher" 10 android:label="@string/app_name" 11 android:roundIcon="@mipmap/ic_launcher_round" 12 android:supportsRtl="true" 13 android:theme="@style/AppTheme"> 14 15 <activity android:name=".MainActivity"> 16 <intent-filter> 17 <action android:name="android.intent.action.MAIN" /> 18 19 <category android:name="android.intent.category.LAUNCHER" /> 20 </intent-filter> 21 </activity> 22 23 <provider 24 android:name="androidx.core.content.FileProvider" 25 android:authorities="com.example.cameraalbumtest.fileprovider" 26 android:exported="false" 27 android:grantUriPermissions="true" 28 xmlns:tools="http://schemas.android.com/tools" 29 tools:replace="android:authorities"> 30 <meta-data 31 android:name="android.support.FILE_PROVIDER_PATHS" 32 android:resource="@xml/file_paths" /> 33 </provider> 34 35 36 </application> 37 38 </manifest>