首先新建一个CameraAlbumTest项目。然后修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/take_photo" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Take Phote" /> <ImageView android:id="@+id/picture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> </LinearLayout>
定义完布局后,定义mainactivity
package com.example.cameraalbumtest; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.widget.ImageView; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; public class MainActivity extends AppCompatActivity { public static final int TAKE_PHOTO=1; private ImageView picture; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取实例 Button takePhoto=(Button) findViewById(R.id.take_photo); picture =(ImageView) findViewById(R.id.picture); takePhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //创建file对象,用于存储拍照后的图片 File outputImage=new File(getExternalCacheDir(),"output_image.jpg");//把图片进行命名 //调用getExternalCacheDir()可以得到手机SD卡的应用关联缓存目录 //所谓的应用关联缓存目录,就是指SD卡中专门用于存放当前应用缓存数据的位置 //具体的路径是/sdcard/Android/data/<package name>/cache //因为从Android 6.0系统开始,读写SD卡被列为了危险权限, // 如果将图片存放在SD卡的任何其他目录,都要进行运行时权限处理才行,而使用应用关联目录则可以跳过这一步。 try { if (outputImage.exists()) {//如果已经存在了图片,则删掉, outputImage.delete(); } outputImage.createNewFile();//将图片放入 }catch (IOException e){ e.printStackTrace(); } //获取Uri对象 //这个Uri对象标识着output_image.jpg这张图片的本地真实路径。 if (Build.VERSION.SDK_INT >= 24) { //调用FileProvider的getUriForFile() 方法将File 对象转换成一个封装过的Uri对象 imageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider", outputImage); //FileProvider则是一种特殊的内容提供器,它使用了和内容提供器类似的机制来对数据进行保护, // 可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。 //第一个参数要求传入Context 对象 //第二个参数可以是任意唯一的字符串 (需要在AndroidManifest.xml中声明) //第三个参数则是我们刚刚创建的File 对象 } else {//若系统的版本低于Android7.0,则调用下面的方法将File对象转换为Uri对象 imageUri = Uri.fromFile(outputImage); } //启动相机程序 Intent intent= new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);//指定图片的输出地址 startActivityForResult(intent,TAKE_PHOTO);//调用startActivityForResult() 来启动活动。 } }); } //使用startActivityForResult() 来启动活动的, // 因此拍完照后会有结果返回到onActivityResult() 方法中。 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case TAKE_PHOTO: if (resultCode == RESULT_OK) {//如果拍照成功 try { // 将拍摄的照片显示出来 //可以调用BitmapFactory的decodeStream() 方法将output_image.jpg这张照片解析成Bitmap 对象 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); picture.setImageBitmap(bitmap);//将Bitmap对象,设置到ImageView中显示出来。 } catch (FileNotFoundException e) { e.printStackTrace(); } } break; default: break; } } }
由于采用到了内容提供器(FileProvider),那么我们自然要在AndroidManifest.xml中对内容提供器进行注册了,如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cameraalbumtest"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.cameraalbumtest.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </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后有
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cameraalbumtest"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" android:authorities="***.fileProvider" android:exported="false" android:grantUriPermissions="true" xmlns:tools="http://schemas.android.com/tools" tools:replace="android:authorities"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> </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>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cameraalbumtest"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.cameraalbumtest.fileprovider" android:exported="false" android:grantUriPermissions="true" xmlns:tools="http://schemas.android.com/tools" tools:replace="android:authorities"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> </manifest>