隐式Intent——调用相机、相册并保存图片

仅为本人学习《Android编程权威指南》记录笔记,可能有诸多错误不妥之处

隐式 intent 调用相机是从《Android编程权威指南》第十六章中学习的:
其实相当于我们用 显式 intent 去启动自己的activity,不过 隐式 intent 启动的是系统应用,我们只需要在 intent 中指出要启动 activity 的功能描述,操作系统就会负责启动相应的应用。

一. 文件存储

我们可以使用 Context类 提供的文件和目录处理方法将文件保存在设备上的私有存储空间(保存SQLite数据文件),但是这只限于存储的文件供应用内部使用,如果是其他应用要读写你的文件,就没那么简单了。
ContentProvider 允许暴露内容 URI 给其他应用,这些应用就可以通过 URI下载或向其写入文件。
Google提供了一个名为 FileProvider的便利类,我们只需要配置一下参数可以了!

1. 首先,声明FileProvider为ContentProvider,并指定权限。

在AndroidMainifest.xml中添加FileProvider声明:

	<activity>...</activity>
	<provider
		android:name="androidx.core.content.FileProvider" 
		//书上是android.support.v4.content.FileProvider,因为从android9.0
 		//(API 28)开始,android.supprot.xxx大多都迁移到了androidx中
 		
		android:authorities=" com.xxx.xxx... .fileprovider"
		//com.xxx.xxx ...为应用包名
		
		android:exported="false"
		//除了你自己以及给予授权的人,其他任何人都不能使用你的FileProvider
		
		android:grantUriPermissions="true">
		//给其他应用授权,允许它们向你指定位置的URI写入文件
		//这个位置信息放在intent中对外发出
		
		<meta-data
			android:name="android.support.FILE_PROVIDER_PATHS"
			android:resource="@xml/files"/>
			//关联路径描述资源即让FIleProvider能找到files.xml(还未创建)
			
	</provider>
	

这里的权限是指一个位置:文件保存地 。 把 FileProvider 与指定的位置关联起来,就相当于给发出请求的其他应用一个目标地。

2. 接下来配置 FileProvider,让它知道该暴露哪些文件。新建一个xml资源文件:

res/xml/files.xml

<paths>
	<files-path name="xxx" path="."/>
</paths>

这是一个描述性文件,其意义为:把私有存储空间的根路径映射为 “xxx”,这个名仅供FileProvider内部使用,不必应用它。

3. 最后指定文件的存放位置就可以了,直接通过Context类的 getFilesDir() 方法得到/data/data/包名/files目录 即activity.getApplicationContext().getFilesDir(),然后就可以直接创建文件了。

二. 使用相机

1. 启动相机当然是为了拍照上传,所以先定义REQUEST常量和照片文件对象:

private static final int REQUEST_CAMERA = 2;
private File mPhotoFile = new File(getAcitivity()
		.getApplicationContext().getFilesDir(),xxxx);
	//这里的Context对象用的是整个应用程序的上下文

2. 新建并启动相机Intent

final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//创建相机Intent

PackageManager packageManager = getAcitivity().getPackageManager();
//得到PackageManager对象

final boolean canTakePhoto = mPhotoFile != null && 
		captureIntent.resolveActivity(packageManager) != null
//判断是否有相应相机Intent的应用

mImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (canTakePhoto) {	//判断相机Intent是否可用
                    Uri uri = FileProvider.getUriForFile(getActivity(),
                            "com.xxx ... .fileprovider", mPhotoFile);
                    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
                    //FileProvider.getUriForFile()会把本地文件路径转换为相机可见的Uri形式

                    List<ResolveInfo> cameraActivities = getActivity()
                            .getPackageManager().queryIntentActivities(captureIntent,
                                    PackageManager.MATCH_DEFAULT_ONLY);
                                    //获取所有的相机Activity

                    for (ResolveInfo activity : cameraActivities) {
                        getActivity().grantUriPermission(activity.activityInfo.packageName,
                                uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    }//为所有的能响应相机Intent的acitivity授予可以写入文件的权限

					startAcitivityForResult(captureIntent,REQUEST_CAMERA);
                }
            }
        });

3. 重写 onAcitivityResult 方法保存图片

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
       if (requestCode == REQUEST_CAMERA) {
           
            Uri uri = FileProvider.getUriForFile(getActivity(),
                    "com.lifeifanzs.memorableintent.fileprovider",
                    mPhotoFIle;
            getActivity().revokeUriPermission(uri,
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
			//相机已经保存文件,就再次调用权限关闭文件的访问
			
            updatePhotoView();//处理照片文件
        }
    }

三. 使用相册
使用相册保存图片是通过获取选择文件的 Uri 来保存的,所以先定义一个Uri类型全局变量

private Uri mImageUri;

新建相册Intent:

Intent albumIntent = new Intent(Intent.ACTION_PICK);//创建相册Intent
albumIntent.setDataAndType(MediaStore.Images
                .Media.EXTERNAL_CONTENT_URI, "image/*");//设置数据和文件类型

四. chooserIntent应用选择器

新建chooserIntent

final Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);//创建选择器Intent
chooserIntent.putExtra(Intent.EXTRA_INTENT, albumIntent);//保存albumIntent

......

mImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (canTakePhoto) {	//判断相机Intent是否可用
                    
                    ......
					
				    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS
				    			, new Intent[]{captureIntent});//保存相机Intent
            }
            startActivityForResult(chooserIntent, REQUEST_CAMERA);
        });

处理intent中的数据

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
       if (requestCode == REQUEST_CAMERA) {

            ......
 
            if (null != data) { //如果intent中保存有数据,即打开的是相册
                mImageUri = data.getData();
            }
            updatePhotoView();//处理照片文件
        }
    }

在 updatePhotView() 中的通过判断 mPhotoFile == null || !mPhotoFile.exists() 和 mImageUri==null 来决定是处理mPhotoFile还是 mImageUri

 if (mPhotoFile == null || !mPhotoFile.exists()) {   //如果对应文件为null或不存在
    if (mImageUri!= null) {   //处理mImageUri   }              
} else {  //处理mPhotoFile   }
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值