在Android项目里引入第三方图片选择库时,PictureSelector是一个比较常见的选择。它由LuckSiege团队维护,提供相册选择、拍照、视频录制、裁剪、压缩等一站式能力。与直接使用Intent跳转系统相册相比,PictureSelector在交互体验和功能扩展上更统一,也避免了不同厂商ROM上Activity结果差异带来的兼容问题。调用方只需通过链式配置声明选择模式、数量、是否裁剪压缩等选项,就能在回调中获取到可用的文件路径或Uri,适合需要快速集成图片上传、头像裁剪、动态发布等功能的业务场景。

接下来本文会从基础集成开始,逐步说明核心参数、拍照视频能力以及版本适配问题。示例代码以Java为主,因为大多数老项目仍然使用Java编写,如果项目使用Kotlin,调用方式基本一致,只需注意语法差异即可。
一、集成PictureSelector与权限声明
第一步是在项目的build.gradle文件中添加Maven仓库和依赖。PictureSelector通过JitPack分发,如果工程中尚未配置JitPack仓库,需要在settings.gradle或项目根目录的build.gradle中声明仓库地址。依赖版本建议使用当前维护的稳定版,避免使用过旧的快照版本导致API不兼容。
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.LuckSiege:PictureSelector:v2.7.1'
implementation 'com.github.bumptech.glide:glide:4.12.0'
}
如果项目中使用了AndroidX,一般还需要在gradle.properties中开启android.enableJetifier=true,确保旧库的support依赖可以映射到AndroidX。不过PictureSelector较新的版本已经适配AndroidX,大多数情况下无需额外处理。
权限方面,在AndroidManifest.xml中需要声明相册和相机权限。Android 10以前使用READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE,Android 13开始需要针对图片和视频单独申请READ_MEDIA_IMAGES与READ_MEDIA_VIDEO。如果应用目标版本较低,可以继续使用旧的存储权限,但为了兼容新系统,建议在运行时按版本分别申请。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
另外,如果应用需要兼容Android 7.0以上的文件访问,还需要为文件提供者声明<provider>节点,并配置对应的file_paths.xml资源。PictureSelector在拍照输出时默认会通过FileProvider生成Uri,若缺少该节点,拍照结果可能返回空或者直接崩溃。
二、核心选择参数与结果回调
最常见的使用方式是打开相册选择图片。通过PictureSelector.create(activity)获取实例,再调用openGallery(PictureMimeType.ofImage())指定图片类型。选择模式分为单选和多选,分别对应PictureConfig.SINGLE和PictureConfig.MULTIPLE。多选时需要设置maxSelectNum限制最大数量,minSelectNum限制最少数量,否则默认不限制上限,可能在用户大量选择时造成内存压力。
PictureSelector.create(this)
.openGallery(PictureMimeType.ofImage())
.imageEngine(GlideEngine.createGlideEngine())
.maxSelectNum(9)
.minSelectNum(1)
.selectionMode(PictureConfig.MULTIPLE)
.isPreviewImage(true)
.isCamera(true)
.isCompress(true)
.compressQuality(80)
.forResult(PictureConfig.CHOOSE_REQUEST);
这里imageEngine是必须配置的,如果不设置,进入选择页面后图片列表会显示空白。PictureSelector本身不包含图片加载逻辑,需要外部提供一个实现ImageEngine接口的引擎,官方示例中通常使用Glide封装一个GlideEngine类。该引擎只需要实现两个方法:加载图片和加载视频封面,内部调用Glide即可。
结果回调在onActivityResult中处理。调用PictureSelector.obtainMultipleResult(data)可以得到一个List<LocalMedia>集合,每一个LocalMedia对象描述了一个被选中的媒体文件。获取原图路径使用getPath(),如果开启压缩,压缩后的文件路径通过getCompressPath()获得;裁剪后的路径则对应getCutPath()。需要注意的是,在高版本系统上,getPath()可能返回content://形式的Uri而不是绝对路径,如果要上传或解码,建议使用ContentResolver读取,不要直接断定为file://路径。
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PictureConfig.CHOOSE_REQUEST && resultCode == RESULT_OK) {
List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);
for (LocalMedia media : selectList) {
String path = media.getPath();
if (media.isCompressed()) {
path = media.getCompressPath();
}
// 将path交给上传或展示逻辑
}
}
}
如果只需要单选头像,可以将selectionMode设置为PictureConfig.SINGLE,并在选择后直接弹出裁剪页面。裁剪参数包括cropW、cropH、isCrop、freeStyleCropEnabled等,若不指定裁剪比例,默认使用自由裁剪。头像场景建议设置cropW = cropH = 300,并关闭自由裁剪,保证输出为正方形。
三、拍照、视频选择与压缩裁剪进阶配置
除了打开相册,PictureSelector也支持单独调用相机拍照。openCamera(PictureMimeType.ofImage())会直接拉起系统相机,拍摄完成后回到选择器或直接回调结果。调用拍照时同样需要设置imageEngine,否则相机拍摄的图片无法预览。如果业务要求照片必须压缩或裁剪,可以在拍照配置中继续追加isCompress、isCrop等参数。
PictureSelector.create(this)
.openCamera(PictureMimeType.ofImage())
.imageEngine(GlideEngine.createGlideEngine())
.isCompress(true)
.compressQuality(85)
.isCrop(true)
.cropW(400)
.cropH(400)
.forResult(PictureConfig.REQUEST_CAMERA);
视频选择和录制使用PictureMimeType.ofVideo()。打开视频相册时需要配置maxSelectNum,通常设置为一,因为视频体积较大,多选容易造成内存和上传压力。录制时长通过videoMaxSecond和videoMinSecond控制,选择完成后返回的LocalMedia对象中会包含视频时长、大小和封面信息。如果同时需要选择图片和视频,可以使用PictureMimeType.ofAll(),但此时需要区分媒体类型,并限制视频大小。
PictureSelector.create(this)
.openGallery(PictureMimeType.ofVideo())
.imageEngine(GlideEngine.createGlideEngine())
.maxSelectNum(1)
.selectionMode(PictureConfig.SINGLE)
.isPreviewVideo(true)
.videoMaxSecond(15)
.videoMinSecond(1)
.forResult(PictureConfig.CHOOSE_REQUEST);
压缩功能默认使用的是Luban压缩算法,参数compressQuality控制输出质量,取值0到100。compressMaxKB用于限制压缩后的最大体积,单位是KB。如果原图本身小于限制值,压缩可能不会再次执行,这属于正常逻辑。裁剪与压缩同时开启时,内部顺序是先裁剪后压缩,因此回调中getCompressPath()返回的路径已经是裁剪并压缩后的最终文件。开发中如果发现压缩不明显,可以先检查原图尺寸和compressMaxKB的设置,避免把压缩阈值设置得过高。
四、分区存储适配与常见问题排查
Android 10引入分区存储后,应用直接访问外部存储公共目录的方式受到限制。PictureSelector内部已经处理了大部分Uri转换和FileProvider逻辑,但开发者在处理选择结果时仍需注意,返回的路径可能是content://media/external/images/media/123这类Uri,不再是以/storage/emulated/0开头的文件路径。如果项目里需要通过文件路径进行图片上传或压缩,建议先用ContentResolver复制到应用私有目录,再拿到真实的File对象。
Android 13进一步收紧了存储权限,相册选择可以使用系统照片选择器而不需要任何存储权限,但如果继续使用PictureSelector打开自定义相册,则需要申请READ_MEDIA_IMAGES。如果用户授权了照片权限但未授权相机权限,拍照入口会失败,因此权限申请要区分场景:只选图片时可按需申请媒体权限,涉及拍照时必须同时检查相机权限。
另一个高频问题是主题冲突。某些项目在AndroidManifest.xml或styles.xml中设置了全局主题,进入PictureSelector后出现标题栏颜色异常、按钮不可见等情况。可以通过.theme(R.style.picture_style)指定自定义主题,或者让宿主Activity继承合适的主题,避免使用透明状态栏或深色背景影响选择器界面。
还有开发者会遇到裁剪后的图片没有保存在预期目录。PictureSelector默认将输出文件放在应用外部缓存目录下的PictureSelector文件夹中,如果长期不清理,会造成存储占用。可以在回调完成后手动删除不再使用的中间文件,或者通过配置setOutputCameraPath和setOutputCropPath把输出目录指向应用私有目录,既便于管理,也能降低公共目录的访问风险。
PictureSelectorAndroid图片选择器图片选择框架修改时间:2026-09-22 07:30:30