Git Product home page Git Product logo

gallerypick's Introduction

本项目已停止维护

本项目的背景是当时没有十分好用的图片选择的库,所以自己写了一个。

目前已经找到一个功能很齐全的库 PictureSelector 推荐大家使用

GalleryPick 图片选择器

GalleryPick 是 Android 自定义相册,实现了拍照、图片选择(单选/多选)、裁剪、ImageLoader无绑定 任由开发者选择

各位的 star 就是对我最大的支持。

图片展示

功能 多选页面 文件夹选择 截图

Gif展示

单选 多选 截图

GalleryPick 功能

  • UI重改
  • 所有功能可配置
  • 解决OOM情况
  • 图片多选、单选
  • ImageLoader 无绑定,任由开发者选择
  • 可直接开启相机
  • 可裁剪、可旋转

版本说明

1.2.1

  • 优化部分代码。

使用说明

步骤一:

本开源代码以关联到 jitpack 网站 ,使用者可以用以下几种方式进行抓取。

通过Gradle使用

Projectbuild.gradle 中 添加:

allprojects {
	repositories {
		...
		maven { url "https://jitpack.io" }
	}
}

appbuild.gradle 中 添加:

dependencies {
      compile 'com.github.YancyYe:GalleryPick:1.2.1'
}

通过maven使用

<repositories>
	<repository>
	    <id>jitpack.io</id>
	    <url>https://jitpack.io</url>
	</repository>
</repositories>
<dependency>
    <groupId>com.github.YancyYe</groupId>
    <artifactId>GalleryPick</artifactId>
    <version>1.2.1</version>
</dependency>

步骤二:创建 图片加载器 (其中可以按照 喜好 使用不同的 第三方图片)

示例:

步骤三:设置 Provider

请在 app 中的 AndroidManifest 中的application标签下添加

 <provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.yancy.gallerypickdemo.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

provider 中的 authorities 可以自己定义为 provider所在的包的名字+provider本身定义的名称 (如果一个设备中出现两个同样的authorities会出现无法安装的情况)

res 中创建xml文件夹,在其中创建文件。文件名自己定义。demo中定义了filepaths.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path
            name="external"
            path="" />
        <files-path
            name="files"
            path="" />
        <cache-path
            name="cache"
            path="" />
    </paths>
</resources>

FileProvider 中设置的内容我就不介绍了,网上一搜一大片。

最后,在设置GalleryConfig 的时候,设置provider,内容为你之前在AndroidManifest中的provider中的authorities设置的值。demo中为:com.yancy.gallerypickdemo.fileprovider

GalleryConfig代码示例

AndroidManifest代码示例

filepaths.xml代码示例

使用方法参考

步骤四:申请权限

代码示例: 在点击开启相册按钮时:

if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG, "需要授权 ");
            if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                Log.i(TAG, "拒绝过了");
                // 提示用户如果想要正常使用,要手动去设置中授权。
                Toast.makeText(mContext, "请在 设置-应用管理 中开启此应用的储存授权。", Toast.LENGTH_SHORT).show();
            } else {
                Log.i(TAG, "进行授权");
                ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_READ_CONTACTS);
            }
        } else {
            Log.i(TAG, "不需要授权 ");
            // 进行正常操作
        }
}

以下是用户授权反馈

Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
	if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
		if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
		    Log.i(TAG, "同意授权");
		    // 进行正常操作。
		} else {
		    Log.i(TAG, "拒绝授权");
		}
	}
}

步骤五:创建监听接口IHandlerCallBack

IHandlerCallBack iHandlerCallBack = new IHandlerCallBack() {
           @Override
           public void onStart() {
               Log.i(TAG, "onStart: 开启");
           }

           @Override
           public void onSuccess(List<String> photoList) {
               Log.i(TAG, "onSuccess: 返回数据");
               for (String s : photoList) {
                   Log.i(TAG, s);
               }
           }

           @Override
           public void onCancel() {
               Log.i(TAG, "onCancel: 取消");
           }

           @Override
           public void onFinish() {
               Log.i(TAG, "onFinish: 结束");
           }

           @Override
           public void onError() {
               Log.i(TAG, "onError: 出错");
            }
};

步骤六:配置 GalleryConfig

可先进行初始配置,除了ImageLoaderIHandlerCallBack之外,其他都是选填,都有默认值。

GalleryConfig galleryConfig = new GalleryConfig.Builder()
                .imageLoader(new GlideImageLoader())    // ImageLoader 加载框架(必填)
                .iHandlerCallBack(iHandlerCallBack)     // 监听接口(必填)
                .provider("com.yancy.gallerypickdemo.fileprovider")   // provider (必填)
                .pathList(path)                         // 记录已选的图片
                .multiSelect(false)                      // 是否多选   默认:false
                .multiSelect(false, 9)                   // 配置是否多选的同时 配置多选数量   默认:false , 9
                .maxSize(9)                             // 配置多选时 的多选数量。    默认:9
                .crop(false)                             // 快捷开启裁剪功能,仅当单选 或直接开启相机时有效
                .crop(false, 1, 1, 500, 500)             // 配置裁剪功能的参数,   默认裁剪比例 1:1
                .isShowCamera(true)                     // 是否现实相机按钮  默认:false
                .filePath("/Gallery/Pictures")          // 图片存放路径
                .build();

可以按照需求进行单项配置,前提需要填好 ImageLoaderIHandlerCallBack,举例:

  galleryConfig.getBuilder().multiSelect(true).build();   // 修改多选
  galleryConfig.getBuilder().isShowCamera(true).build();   // 修改显示相机
  galleryConfig.getBuilder().imageLoader(new PicassoImageLoader()).build(); // 修改图片加载框架

步骤七:启动GalleryPick图片选择器

GalleryPick.getInstance().setGalleryConfig(galleryConfig).open(mActivity);

其他功能使用方法说明:

一:裁剪功能使用说明

注意:裁剪功能只能在单选时、直接开启相机时生效。

GalleryConfig galleryConfig = new GalleryConfig.Builder()
                .imageLoader(new GlideImageLoader())    // ImageLoader 加载框架(必填)
                .iHandlerCallBack(iHandlerCallBack)     // 监听接口(必填)
                .provider("com.yancy.gallerypickdemo.fileprovider")   // provider (必填)
                .pathList(path)                         // 记录已选的图片
                .crop(true)                             // 快捷开启裁剪功能,仅当单选 或直接开启相机时有效
                .isShowCamera(true)                     // 是否现实相机按钮  默认:false
                .filePath("/Gallery/Pictures")          // 图片存放路径
                .build();
GalleryPick.getInstance().setGalleryConfig(galleryConfig).open(mActivity);

如果需要自定义裁剪框的比例,可按照以下方法设置:

GalleryConfig galleryConfig = new GalleryConfig.Builder()
                .imageLoader(new GlideImageLoader())    // ImageLoader 加载框架(必填)
                .iHandlerCallBack(iHandlerCallBack)     // 监听接口(必填)
                .provider("com.yancy.gallerypickdemo.fileprovider")   // provider (必填)
                .pathList(path)                         // 记录已选的图片
                .crop(true, 1, 1, 500, 500)           // 配置裁剪功能的参数,   默认裁剪比例 1:1
                .isShowCamera(true)                     // 是否现实相机按钮  默认:false
                .filePath("/Gallery/Pictures")          // 图片存放路径
                .build();
GalleryPick.getInstance().setGalleryConfig(galleryConfig).open(mActivity);

裁剪图片存放在 filePath 文件夹下的 crop 目录下。内部创建了忽略文件,手机系统扫描不到此文件目录下的媒体文件,防止裁剪图片显示在相册中,影响心情。

二:直接开启相机,其中有三种方法。

方法一:

GalleryConfig 中设置直接开启相机的标识位。

GalleryConfig galleryConfig = new GalleryConfig.Builder()
          .iHandlerCallBack(iHandlerCallBack)     // 监听接口(必填)
          .filePath("/Gallery/Pictures")          // 图片存放路径   (选填)
          .isOpenCamera(true)                  // 直接开启相机的标识位
          .build();

GalleryPick.getInstance().setGalleryConfig(galleryConfig).open(mActivity);
方法二:

如果已经设置好了 GalleryConfig 可以使用单项参数修改的方法来开启相机。

galleryConfig.getBuilder().isOpenCamera(true).build();
GalleryPick.getInstance().setGalleryConfig(galleryConfig).open(mActivity);
方法三:

为了方便使用,在不变动开启相册的GalleryConfig的情况下,我还添加了以下方法。

 GalleryPick.getInstance().setGalleryConfig(galleryConfig).openCamera(mActivity);

这个方法可以直接使用。不需要在GalleryConfig中添加标志位,或者进行单项修改。方便用户使用。

三:深度自定义UI方法

可能有很多用户对 GalleryPick 里面的界面还有些不满意。没关系,接下来我来教大家如何自己定义其中的颜色。

下面举个简单的例子:

1)

我在 GalleryPick 中的 gallery_title.xml 中设置了标题栏的颜色为 @color/gallery_blue 用户可以在 app 中的 colors.xml 中定义一个名为 gallery_blue 的颜色:

<resources>
    <color name="gallery_blue">#FF4081</color>
</resources>

这样就达到了覆盖资源文件的效果。从而达到自定义UI。

2)

有些朋友会问,我标题栏设置了白色,但是标题栏的字体和图标也是白色的,那该怎么办? 下面来讲一下方法,因为是覆盖资源文件,所以在 app 中创建 gallery_title.xml , 先将 GalleryPick 中的 gallery_title.xml 代码copy过去,然后就简单了。将TextViewtextColor中的颜色颜色换一下就好了。同样,返回按钮可以改变一下 ImageViewsrc,很简单。

旧版本记录

1.2.0

  • 忽略裁剪图片,返回相机拍摄的照片。

1.1.8

  • 优化 Provider 防止两个以上 App 使用 GalleryPick会出现安装不上的问题。 (修改详情

1.1.7

  • 修复android 4.x 打开相机崩溃的bug

1.1.6

  • 修复android 7.x 打开相机崩溃的bug

1.1.4

  • 优化相册系统。拍摄、裁剪的图片,只有选中时才在相册显示。

1.1.3

  • 修改裁剪所存在的bug

1.1.2

  • 添加通过覆盖资源的方式,修改截图页面的配色。(使用方法参考

1.1.1

  • 修复直接开启相机所存在的问题

1.1.0

1.0.4

1.0.3

  • 提供单选、多选、以及相机拍照功能。
  • 自定义ImageLoader

感谢(Thanks)

关于作者

gallerypick's People

Contributors

yancyye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gallerypick's Issues

如何自动选中最近拍的图片

很棒的项目,在学习中。现在我想在加载的时候自动选择一个小时内拍的图片,应该在哪里添加这个功能呢?

记录已选的图片怎么去掉?

RT,在选择图片完成后,再次选择时,不想记录之前已选的图片,希望重新选择所有图片,请问应该怎么办?

额,挂了

java.lang.NullPointerException: Attempt to invoke interface method 'boolean com.yancy.gallerypick.widget.GalleryImageView$OnImageViewListener.verifyDrawable(android.graphics.drawable.Drawable)' on a null object reference
at com.yancy.gallerypick.widget.GalleryImageView.verifyDrawable(GalleryImageView.java:48)
at android.view.View.invalidateDrawable(View.java:16684)
at android.widget.ImageView.invalidateDrawable(ImageView.java:244)
at android.graphics.drawable.Drawable.invalidateSelf(Drawable.java:408)
at android.graphics.drawable.Drawable.setBounds(Drawable.java:203)
at android.view.View.drawBackground(View.java:16277)
at android.view.View.draw(View.java:16051)
。。。。。无用调用栈

gif oom

加载gif的时候很容易oom呢

我是直接调用相机会出现出现找不到类啊

Unable to start activity ComponentInfo{com.yancy.gallerypick.activity.GalleryPickActivity}: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Gallery/Pictures/20180131120326.jpg

2个错误标记 获取不到设备内存的问题我设置成root-paht 也没有用

红米note4调用图库选择拍照崩溃

遇到了以下几个问题:
1.拍照完成后,一闪而过不显示拍照图片,实际拍照成功了,也在SD卡生成了图片文件
2.选择照片时,那个图库里面有很多张都是默认图,但实际上应该是有效图片,换言之就是图库没刷新(不知道我说的对不对)
3.我先用的Picasso出现的上述问题,换glide后,图片显示没问题了,但是图库没有及时刷新
qq 20170330145830

这个Invalid image.有没有问题的。

Invalid image.
java.io.IOException: Invalid marker: 89
at android.media.ExifInterface.getJpegAttributes(ExifInterface.java:1616)
at android.media.ExifInterface.loadAttributes(ExifInterface.java:1341)
at android.media.ExifInterface.(ExifInterface.java:1058)
at com.yalantis.ucrop.task.BitmapCropTask.crop(BitmapCropTask.java:150)
at com.yalantis.ucrop.task.BitmapCropTask.doInBackground(BitmapCropTask.java:94)
at com.yalantis.ucrop.task.BitmapCropTask.doInBackground(BitmapCropTask.java:35)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)

新bug:GalleryPickActivity点击返回键,界面不更新

GalleryPickActivity中 返回键应该与完成键逻辑相同:
btnGalleryPickBack.setOnClickListener(new View.OnClickListener() {
@OverRide
public void onClick(View v) {
// 从完成键那边加过来的。。。
if (resultPhoto != null && resultPhoto.size() > 0) {
mHandlerCallBack.onSuccess(resultPhoto);
exit();
}

            mHandlerCallBack.onCancel();
            exit();
        }
    });

使用provider同时依赖GalleryPick报Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed with multiple errors, see logs

Information:Gradle tasks [:app:generateDebugSources, :app:generateDebugAndroidTestSources]
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:checkDebugManifest
:app:preBetaBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAnimatedVectorDrawable2501Library UP-TO-DATE
:app:prepareComAndroidSupportAppcompatV72501Library UP-TO-DATE
:app:prepareComAndroidSupportDesign2400Library UP-TO-DATE
:app:prepareComAndroidSupportRecyclerviewV72501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportCompat2501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportCoreUi2501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportCoreUtils2501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportFragment2501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportMediaCompat2501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportV42501Library UP-TO-DATE
:app:prepareComAndroidSupportSupportVectorDrawable2501Library UP-TO-DATE
:app:prepareComBigkooSvprogresshud102Library UP-TO-DATE
:app:prepareComDaimajiaSwipelayoutLibrary120Library UP-TO-DATE
:app:prepareComGithubYancyYeGalleryPick117Library UP-TO-DATE
:app:prepareComJakewhartonButterknife810Library UP-TO-DATE
:app:prepareComTencentBuglyCrashreport_upgrade123Library UP-TO-DATE
:app:prepareComTencentBuglyNativecrashreport312Library UP-TO-DATE
:app:prepareComYalantisUcrop220Library UP-TO-DATE
:app:prepareComYancyImageselectorImageselector130Library UP-TO-DATE
:app:prepareComZhyPercentSupportExtends111Library UP-TO-DATE
:app:prepareDeHdodenhofCircleimageview210Library UP-TO-DATE
:app:prepareDebugDependencies
:app:compileDebugAidl
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources
:app:processDebugManifest
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:16:5-81 Warning:
Element uses-permission#android.permission.WRITE_EXTERNAL_STORAGE at AndroidManifest.xml:16:5-81 duplicated with element declared at AndroidManifest.xml:11:5-81
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:24:5-76 Warning:
Element uses-permission#android.permission.ACCESS_WIFI_STATE at AndroidManifest.xml:24:5-76 duplicated with element declared at AndroidManifest.xml:10:5-76
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:26:5-79 Warning:
Element uses-permission#android.permission.ACCESS_NETWORK_STATE at AndroidManifest.xml:26:5-79 duplicated with element declared at AndroidManifest.xml:5:5-79
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:28:5-76 Warning:
Element uses-permission#android.permission.CHANGE_WIFI_STATE at AndroidManifest.xml:28:5-76 duplicated with element declared at AndroidManifest.xml:9:5-76
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:32:5-81 Warning:
Element uses-permission#android.permission.WRITE_EXTERNAL_STORAGE at AndroidManifest.xml:32:5-81 duplicated with element declared at AndroidManifest.xml:16:5-81
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:34:5-84 Warning:
Element uses-permission#android.permission.MOUNT_UNMOUNT_FILESYSTEMS at AndroidManifest.xml:34:5-84 duplicated with element declared at AndroidManifest.xml:15:5-84
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:37:5-75 Warning:
Element uses-permission#android.permission.READ_PHONE_STATE at AndroidManifest.xml:37:5-75 duplicated with element declared at AndroidManifest.xml:30:5-75
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:38:5-79 Warning:
Element uses-permission#android.permission.ACCESS_NETWORK_STATE at AndroidManifest.xml:38:5-79 duplicated with element declared at AndroidManifest.xml:26:5-79
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:39:5-76 Warning:
Element uses-permission#android.permission.ACCESS_WIFI_STATE at AndroidManifest.xml:39:5-76 duplicated with element declared at AndroidManifest.xml:24:5-76
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:41:5-84 Warning:
Element uses-permission#android.permission.MOUNT_UNMOUNT_FILESYSTEMS at AndroidManifest.xml:41:5-84 duplicated with element declared at AndroidManifest.xml:34:5-84
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:42:5-81 Warning:
Element uses-permission#android.permission.WRITE_EXTERNAL_STORAGE at AndroidManifest.xml:42:5-81 duplicated with element declared at AndroidManifest.xml:32:5-81
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:47:5-75 Warning:
Element uses-permission#android.permission.READ_PHONE_STATE at AndroidManifest.xml:47:5-75 duplicated with element declared at AndroidManifest.xml:37:5-75
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:48:5-76 Warning:
Element uses-permission#android.permission.ACCESS_WIFI_STATE at AndroidManifest.xml:48:5-76 duplicated with element declared at AndroidManifest.xml:39:5-76
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:49:5-79 Warning:
Element uses-permission#android.permission.ACCESS_NETWORK_STATE at AndroidManifest.xml:49:5-79 duplicated with element declared at AndroidManifest.xml:38:5-79
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:53:5-73 Warning:
Element uses-permission#android.permission.WRITE_SETTINGS at AndroidManifest.xml:53:5-73 duplicated with element declared at AndroidManifest.xml:12:5-73
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:55:5-68 Warning:
Element uses-permission#android.permission.WAKE_LOCK at AndroidManifest.xml:55:5-68 duplicated with element declared at AndroidManifest.xml:8:5-68
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:58:5-68 Warning:
Element uses-permission#android.permission.READ_LOGS at AndroidManifest.xml:58:5-68 duplicated with element declared at AndroidManifest.xml:40:5-68
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:61:5-68 Warning:
Element uses-permission#android.permission.BLUETOOTH at AndroidManifest.xml:61:5-68 duplicated with element declared at AndroidManifest.xml:13:5-68
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:244:13-64 Error:
Attribute provider#android.support.v4.content.FileProvider@authorities value=(com.sh_rw.shrenwei.fileProvider) from AndroidManifest.xml:244:13-64
is also present at [com.github.YancyYe:GalleryPick:1.1.7] AndroidManifest.xml:21:13-69 value=(com.yancy.gallerypick.fileprovider).
Suggestion: add 'tools:replace="android:authorities"' to element at AndroidManifest.xml:242:9-250:20 to override.
D:\duke\RW_Android\SHRenWei\app\src\main\AndroidManifest.xml:249:17-55 Error:
Attribute meta-data#android.support.FILE_PROVIDER_PATHS@resource value=(@xml/provider_paths) from AndroidManifest.xml:249:17-55
is also present at [com.github.YancyYe:GalleryPick:1.1.7] AndroidManifest.xml:26:17-50 value=(@xml/filepaths).
Suggestion: add 'tools:replace="android:resource"' to element at AndroidManifest.xml:247:13-249:57 to override.
See http://g.co/androidstudio/manifest-merger for more information about the manifest merger.
:app:processDebugManifest FAILED
Error:Execution failed for task ':app:processDebugManifest'.

Manifest merger failed with multiple errors, see logs

java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord

5.0以上的系统没问题,4.0的系统上,报上述错误;
GalleryPickActivity.java的showCameraAction()函数,修改一下:
private void showCameraAction() {
// 跳转到系统照相机
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(mActivity.getPackageManager()) != null) {
// 设置系统相机拍照后的输出路径
// 创建临时文件
cameraTempFile = FileUtils.createTmpFile(mActivity, galleryConfig.getFilePath());
Uri imageUri = FileProvider.getUriForFile(mContext, "com.yancy.gallerypick.fileprovider", cameraTempFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

        List<ResolveInfo> resInfoList = mContext.getPackageManager().queryIntentActivities(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;
            mContext.grantUriPermission(packageName, imageUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }

        startActivityForResult(cameraIntent, REQUEST_CAMERA);
    } else {
        Toast.makeText(mContext, R.string.gallery_msg_no_camera, Toast.LENGTH_SHORT).show();
        galleryConfig.getIHandlerCallBack().onError();
    }
}

com.yancy.gallerypick.config.GalleryConfig.Builder造成内存

通过MAT查看内存,发现使用图片选择器的那个Activity没有销毁,通过MAT查看引用com.yancy.gallerypick.config.GalleryConfig.Builder这个类没有释放
public GalleryConfig build() {
if (galleryConfig == null) {
galleryConfig = new GalleryConfig(this);
} else {
galleryConfig.setBuilder(this);
}
return galleryConfig;
}
是否是这里有循环引用造成的还是其它问题

android4.1系统崩溃

FATAL EXCEPTION: main
java.lang.SecurityException: Uid 10158 does not have permission to uri content://com.yancy.gallerypickdemo.fileprovider/external/storage/sdcard0/Vitek/jcoa/pics/20170529152551.jpg
at android.os.Parcel.readException(Parcel.java:1430)
at android.os.Parcel.readException(Parcel.java:1384)
at android.app.ActivityManagerProxy.grantUriPermission(ActivityManagerNative.java:3178)
at android.app.ContextImpl.grantUriPermission(ContextImpl.java:1631)
at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:453)
at com.yancy.gallerypick.activity.GalleryPickActivity.showCameraAction(GalleryPickActivity.java:343)
at com.yancy.gallerypick.activity.GalleryPickActivity.access$300(GalleryPickActivity.java:46)
at com.yancy.gallerypick.activity.GalleryPickActivity$2.OnClickCamera(GalleryPickActivity.java:150)
at com.yancy.gallerypick.adapter.PhotoAdapter$1.onClick(PhotoAdapter.java:71)
at android.view.View.performClick(View.java:4107)
at android.view.View$PerformClick.run(View.java:17160)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5536)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1074)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:841)
at dalvik.system.NativeStart.main(Native Method)

小米5在调用系统摄像头拍照后返回,有时会崩溃

小米5(android 7.0, API 24)在调用系统摄像头拍照后返回,有时会崩溃,但没有stacktrace,与正常调用不同的提示是下面一行:

W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable

使用酷派和乐视手机测试过,没有出现类似情况。

多谢解答~

因为单例模式产生的bug

我们在调用的时候用到这个方法,其中galleryConfig是由GalleryConfig.build出来的,注意到他是一个静态的对象,所以所有的galleryConfig其实就是共用的一个对象;
我若在MainActivity里面设置了一个全局变量类似下面这个:
private GalleryConfig galleryConfig = new GalleryConfig.Builder()
.imageLoader(new GlideImageLoader()) // ImageLoader 加载框架(必填)
.iHandlerCallBack(iHandlerCallBack) // 监听接口(必填)
.provider("minihou.net.homeschoolconnect.fileprovider") // provider (必填)
.pathList(listPath) // 记录已选的图片
.crop(true) // 快捷开启裁剪功能,仅当单选 或直接开启相机时有效
.isShowCamera(true) // 是否现实相机按钮 默认:false
.filePath("/Gallery/Pictures") // 图片存放路径
.build();

然后我去下一个页面 又设置了一个galleryConfigNew:

private GalleryConfig galleryConfigNew = new GalleryConfig.Builder()
.imageLoader(new GlideImageLoader()) // ImageLoader 加载框架(必填)
.iHandlerCallBack(iHandlerCallBack) // 监听接口(必填)
.provider("minihou.net.homeschoolconnect.fileprovider") // provider (必填)
.pathList(listPath) // 记录已选的图片
.crop(true) // 快捷开启裁剪功能,仅当单选 或直接开启相机时有效
.isShowCamera(true) // 是否现实相机按钮 默认:false
.filePath("/Gallery/Pictures") // 图片存放路径
.build();

你会发现这个galleryConfigNew和我上一个页面的galleryConfig是一个对象。然而此时我的galleryConfigNew的配置项已经发生改变。

我按返回键回到我的上一个页面,因为我刚才在下一个页面已经改变了这个config,那么此时我这个页面的galleryConfig已经发生了变化,我必须要重置,否则配置已经发生变化。

建议

看着写得很好,功能可以再扩展一些,建议开个QQ群方便讨论

提个建议

在多选时,用相机拍完照后,把拍完的照片加到下面的列表中并选中。

问个问题

大神你好,我写了一个自定义的组合控件,用来上传图片用的功能很简单就是ImageView和TextView的组合,在控件里使用了你的库,选择图片然后加载到ImageView上,现在问题是这样的,页面上有多个这种控件,选择图片后,图片总是加载到最后一个控件上,不管是点击那个控件都是响应在最后的控件上,不知道是什么原因?
自定义控件代码如下:

public class ImagePicker extends RelativeLayout implements View.OnClickListener {


    private Context mContext;

    private ImageView mImageView;//这个是要用来展示上传的图片的
    private TextView mTextView;
    private ImageView mIvEx;

    private String mResIdEx;

    private String mTitleText;
    private float mTitleSize;
    private int mTitleColor;
    private Drawable mDrawableEx;

    private String mImageUrl;

    private PermissionsChecker mPermissionsChecker; // 权限检测器

    // 所需的全部权限
    static final String[] PERMISSIONS = new String[]{
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA

    };
    private static final int REQUEST_CODE = 0; // 请求码


    private BottomSheetDialog mDialog;
    private GalleryConfig mGalleryConfig;

    public String getTitleText() {
        return mTitleText;
    }


    public void setTitleText(String titleText) {
        this.mTitleText = titleText;
        mTextView.setText(mTitleText);
    }

    public String getImageUrl() {
        return mImageUrl;
    }


    public ImagePicker(Context context) {
        super(context);
        mContext = context;
    }

    public ImagePicker(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        if (!isInEditMode()) {
            LayoutInflater.from(context).inflate(R.layout.image_picker, this, true);
        }
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ImagePicker);
        mDrawableEx = typedArray.getDrawable(R.styleable.ImagePicker_imageEx);
        mResIdEx = typedArray.getString(R.styleable.ImagePicker_imageExResId);
        mTitleText = typedArray.getString(R.styleable.ImagePicker_titleText);
        mTitleColor = typedArray.getColor(R.styleable.ImagePicker_titleTextColor, Color.BLACK);
        typedArray.recycle();
    }

    public ImagePicker(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (!isInEditMode()) {
            mImageView = (ImageView) findViewById(R.id.ip_image);
            mTextView = (TextView) findViewById(R.id.ip_text);
            mIvEx = (ImageView) findViewById(R.id.ip_imageEx);
            if (!TextUtils.isEmpty(mTitleText)) {
                mTextView.setText(mTitleText);
            }
            if (mDrawableEx != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    mIvEx.setBackground(mDrawableEx);
                }
            }
            mImageView.setOnClickListener(this);
            mIvEx.setOnClickListener(this);
        }

        //图库初始化
        initGalleryPicker();
        mPermissionsChecker = new PermissionsChecker(mContext);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ip_image:
                showDialog();
                break;
            case R.id.ip_imageEx:
                lookEx();
                break;
            case R.id.tv_takePhoto:
                takePhoto();
                dismissDialog();
                break;
            case R.id.tv_Gallery:
                selectGallery();
                dismissDialog();
                break;
            case R.id.tv_cancel:
                dismissDialog();
                break;

        }
    }

    private void lookEx() {
        Resources res = getResources();

        int drawable = res.getIdentifier(mResIdEx, "drawable", mContext.getPackageName());


        mContext.startActivity(new Intent(mContext, ImageActivity.class)
                .putExtra(Constants.IMAGE, drawable));
    }

    private void takePhoto() {
        GalleryPick.getInstance().setGalleryConfig(mGalleryConfig).openCamera((Activity) mContext);
    }
    //打开相机
    private void dismissDialog() {
        if (mDialog != null && mDialog.isShowing()) {
            mDialog.dismiss();
        }
    }
    //从图库选择
    private void selectGallery() {
        if (mPermissionsChecker.lacksPermissions(PERMISSIONS)) {
            PermissionsActivity.startActivityForResult((Activity) mContext, REQUEST_CODE, PERMISSIONS);
        }
        mGalleryConfig.getBuilder().isOpenCamera(false).build();
        GalleryPick.getInstance().setGalleryConfig(mGalleryConfig).open((Activity) mContext);
    }

    private void showDialog() {
        if (mDialog == null) {
            mDialog = new BottomSheetDialog(mContext);
            View dialogView = LayoutInflater.from(mContext).inflate(R.layout.image_picker_dialog, null);
            TextView tvTakePhoto = (TextView) dialogView.findViewById(R.id.tv_takePhoto);
            TextView tvGallery = (TextView) dialogView.findViewById(R.id.tv_Gallery);
            TextView tvCancel = (TextView) dialogView.findViewById(R.id.tv_cancel);
            tvTakePhoto.setOnClickListener(this);
            tvGallery.setOnClickListener(this);
            tvCancel.setOnClickListener(this);
            mDialog.setContentView(dialogView);
        }
        mDialog.show();
    }

    private void initGalleryPicker() {
        mGalleryConfig = new GalleryConfig.Builder()
                .imageLoader(new GlideImageLoader())
                .iHandlerCallBack(iHandlerCallBack)
                .crop(true)
                .build();
    }

    IHandlerCallBack iHandlerCallBack = new IHandlerCallBack() {
        @Override
        public void onStart() {
        }

        @Override
        public void onSuccess(List<String> photoList) {
            if (photoList.size() > 0) {
                String path = photoList.get(0);
                //图片展示,当有多个控件时,总是加载到最后一个控件上
                Glide.with(mContext)
                        .load(path)
                        .centerCrop()
                        .into(mImageView);
                mTextView.setVisibility(View.GONE);
               //上传
                Bitmap bitmap = ImageUtils.getBitmap(path);
                byte[] imgByte = ImageUtils.bitmap2Bytes(bitmap, Bitmap.CompressFormat.JPEG);
                String imgString = Constants.BASE64_ENCODE + EncodeUtils.base64Encode2String(imgByte);
                RetrofitHelper.getInstance().upload(new RxSubscriber<String>(mContext) {
                    @Override
                    public void onNext(String s) {
                        mImageUrl = s;
                    }
                }, imgString);
            }
        }

        @Override
        public void onCancel() {
        }

        @Override
        public void onFinish() {
        }

        @Override
        public void onError() {
        }
    };


}

如果外部存储卡不能用。会出错。

FATAL EXCEPTION: main
Process: com.yancy.gallerypickdemo, PID: 6500 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.yancy.gallerypickdemo/com.yancy.gallerypick.activity.GalleryPickActivity}: java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.yancy.gallerypickdemo/cache/20170220200606.jpg
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2441)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2501)
 at android.app.ActivityThread.access$1000(ActivityThread.java:153)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1367)
 at android.os.Handler.dispatchMessage(Handler.java:102)
 at android.os.Looper.loop(Looper.java:154)
 at android.app.ActivityThread.main(ActivityThread.java:5462)
 at java.lang.reflect.Method.invoke(Native Method)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
 Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.yancy.gallerypickdemo/cache/20170220200606.jpg
 at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
 at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
 at com.yancy.gallerypick.activity.GalleryPickActivity.showCameraAction(GalleryPickActivity.java:332)
 at com.yancy.gallerypick.activity.GalleryPickActivity.onCreate(GalleryPickActivity.java:99)
 at android.app.Activity.performCreate(Activity.java:6303)
 at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2394)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2501) 
 at android.app.ActivityThread.access$1000(ActivityThread.java:153) 
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1367) 
 at android.os.Handler.dispatchMessage(Handler.java:102) 
 at android.os.Looper.loop(Looper.java:154) 
 at android.app.ActivityThread.main(ActivityThread.java:5462) 
 at java.lang.reflect.Method.invoke(Native Method) 
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739) 
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629) 

log如上。是FileProvider的问题

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.