Wallpaper模块(一)

Wallpaper模块(一)

Picker是一个用于从交互的选取图片类的Activity中获得所选图片的类. Tool.

<1>对外开放Listen接口,取图成功<会返回取得的资源的Uri>和取图失败<返回原因>.

<2>Picker因为定位是一个tool,因此设计为单例模式,load Class 即生成实例. early-init.

<3>因为Picker其实只在WallPaper模块被使用,因此在设计的时候没有考虑pendingTask, 如果一个pickTask正在进行,
又来了一个,会直接fail,并告知 "当前正在pick" 为做原因.
有一个pickingFlag会被维护.

<4>Picker的取图是通过其他有选图功能的Activity实现的,因此Picker的取图其实是startActivityForResult<需要Result来
承载选取图片的Uri>. 如果在startActivityForResult中间出了Exception<比如没有这种Activity>,那么就认为这次pick fail.
注意startActivityForResult只能由Activity而不是Context调用.
Result会在后面通过原Activity的onActivityResult()回调,并附带结果和requestCode,
在这个回调函数里通过requestCode来进一步将之转角给Picker来处理.

<5>PickTask可以细分为3类:
    (1)MediaStore.ACTION_IMAGE_CAPTURE, 如果有相机并且设置了从相机取<一个flag>,直接从相机拍一张.
这里还需要对Intent做一些特殊的处理: 首先要通过putExtra(MediaStore.EXTRA_OUTPUT, locationUri);设置这个才能将
拍摄的照片存放在指定的location中,否则是在默认目录下.
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION)
* If set, the recipient of this Intent will be granted permission to
* perform read/write operations on the URI in the Intent's data and any URIs
* specified in its ClipData.
这样才有权限将照片存入location.

    (2)Intent.ACTION_GET_CONTENT,从已经有的图片中选择,在intent setType("image/*")来实现这个效果;
利用MIME过滤, 注意要小写.和RFC不一样。
上面的设置也要进行一边。
建议使用前看看源码注释.

    (3)得到图片以后,可能还需要裁剪一下<crop>,
crop需要指定输入Uri,输出的Uri,以及要裁剪的width/height.
在Intent的setDataAndType(输入Uri,"image/*");
可以尝试直接使用android的源生crop:new Intent("com.android.camera.action.CROP")
同样设置,然后对于crop还有一些专有设置,
intent.putExtra("crop", "true");
intent.putExtra("scale", true);
intent.putExtra("scaleUpIfNeeded", true);
intent.putExtra("aspectX", width);
intent.putExtra("aspectY", height);
intent.putExtra("outputX", width);
intent.putExtra("outputY", height);
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
在上面的尝试也失败的情况下,可以直接试试CropImageIntentBuilder.
Intent的用法博大精深,纯记不现实,基本上每次都会看源码注释.

<6>在发起真正的Intent前,如果版本 <= ICS,那么还要检查sdcard是否挂载正常.如果没有,直接fail.
如果本次的需求指明了要进行crop, 那么会用一个临时文件作为转存的Uri地址.
如果指明使用camera,那么会尝试一次<有可能失败,如果没有摄像头或者别的问题>

<7>在用户选取完图片回调处理requestCode时,
如果是取图或者拍照,那么检查返回的Intent是否为null以及其getData()是否为null<getData()中含有转存文件的Uri>,
如果OK,那么就将转存的Uri的内容全部复制到另外的Uri中,因为会转存到Assets中,
Assets目录是开发期的一个概念,真正安装完以后的APP目录下是没有的:
http://stackoverflow.com/questions/10166638/access-android-apk-asset-data-directly-in-c-without-asset-manager-and-copying
所以要使用context.getContentResolver().openAssetFileDescriptor(Uri, "rw").createOutputStream()>
而转存的Uri可以直接context.getContentResolver().openInputStream(inputUri),
这写stream也需要按照常规的finally close().
如果指定了将转存的临时Uri删除,在finally里也会
context.getContentResolver().delete(Uri, null, null);因为是整个文件,所以后面两个参数可以为null.
在转存Asset成功以后,如果还需要Crop,那么会重新start 一个 crop的Intent,并检测结果.
否则说明这次PickTask完成<保险起见,最开始判断一下是不是确实在picking,有果必有因>,
调用Listener的回调,最后将picking flag reset.

<8>进行一次Pick操作本身的构造 通过 builder模式 实现,因为Picker是一个单例的tool,
因此完全可以将其包裹在PickTaskBuilder中,PickTaskBuilder 会提供几个set方法
<仿效Notifictaion.Builder,不同的是这个builder本质上不会build一个实例对象,而是build了一次操作,因此会有execute方法>
并且返回就是PickTaskBuilder实例本身,实现了 new Builder(A,B,C),setD(D1).setE(E1).execute().
当然这里的builder模式的作用其实不是很大,只是提供了对一次pick操作的灵活配置<各种set>.

<9>在从转存Uri到AssetUri的copy IO过程中,这个过程因为很快,所以当时就给放在了main Thread中了。
其实应该单独开一个线程的.尽管如此,在外部使用PickTaskBuilder来选取图片时,还是应该将其看作是一个异步的过程,

应该认为注册的Listener的回调不是同步的,而是未来一个时间点.在回调应该检查当时发出请求的环境是否还一样<物是人非,人面桃花>.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值