Wallpaper模块(1) 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的取图实际上是startactivityForresulter<需要Result 承载选择图片的Uri>. 如果Exceptionn在startactivityForsult中间出现<例如,没有这样的Activity>,所以我觉得这次pickk这次是pickck fail. 注意startactivityForesult只能由Activity调用,而不是Context. Result将在后面通过原Activityonactivityresult()进行回调,并附带结果和requestcode, 在这个回调函数中,通过requestcode进一步将其转角处理给Picker. <5>PickTask可分为三类: (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. Setdatandtype(输入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()); 如果上述尝试失败,可以直接尝试Cropimageintbuilder. Intent的用法博大精深,纯记不现实,基本上每次都会看源码注释. <6>在发起真正的Intent之前,如果版本 <= ICS,然后检查sdcard是否正常挂载。如果没有,直接faill. 如果这个需求指明了crop, 然后将使用临时文件作为转存Uri地址. 如果说明使用camera,请尝试一次<有可能失败,如果没有摄像头或其他问题> <7>当用户选择图片回调处理requestCode时, 如果是取图或拍照,检查返回的Intent是否为null,其getdata()是否为nulll<getData()含有转存文件的Uri>, 如果OK,然后将转存的Uri内容全部复制到另一个Uri中,因为将转存到Assets中, Assets目录是开发期的概念,APP目录下真正安装后没有: https://www.tulingxueyuan.cn/d/file/p/20230524/ofhcwddlnl2 所以要使用contexttext.getContentResolver().openAssetFileDescriptor(Uri, "rw").createOutputStream()> 转存的Uri可以直接contextt.getContentResolver().openInputStream(inputUri), 这个stream也需要按照常规的finally来写 close(). 如果指定删除转存的临时Uri,也会在finally中 context.getContentResolver().delete(Uri, null, null);因为是整个文件,所以后两个参数可以是nulll. 转存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>copy从转存Uri到AssetUri 在IO过程中,因为这个过程很快,当时就把它放在main里了 中了Thread。 事实上,应该单独打开一个线程。然而,当使用Picktaskbuilder在外部选择图片时,它仍然应该被视为一个异步过程,
应该认为,注册Listener的回调不是同步的,而是未来的时间点。回调时,应检查当时要求的环境是否相同<人是非,人面桃花>.