Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load a URI with "content://" prefix using Glide Android?

I'm trying to load a Contact photo with URI "content://com.android.contacts/contacts/295" by using Glide.

When I use

Glide.with(context).load(Uri.parse(contactPhoto).into(imageview)

Glide gives me a FileNotFoundException

java.io.FileNotFoundException: File does not exist; URI: content://com.android.contacts/contacts/264, calling user: android.uid.shared:10006, calling package is one of: [com.android.providers.contacts, com.android.contacts, com.android.providers.userdictionary]
        at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:146)
        at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:689)
        at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1080)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:921)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:848)
        at com.bumptech.glide.load.data.FileDescriptorLocalUriFetcher.loadResource(FileDescriptorLocalUriFetcher.java:21)
        at com.bumptech.glide.load.data.FileDescriptorLocalUriFetcher.loadResource(FileDescriptorLocalUriFetcher.java:14)
        at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:44)
        at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.loadData(ImageVideoModelLoader.java:83)
        at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.loadData(ImageVideoModelLoader.java:53)
        at com.bumptech.glide.load.engine.DecodeJob.decodeSource(DecodeJob.java:170)
        at com.bumptech.glide.load.engine.DecodeJob.decodeFromSource(DecodeJob.java:128)
        at com.bumptech.glide.load.engine.EngineRunnable.decodeFromSource(EngineRunnable.java:122)
        at com.bumptech.glide.load.engine.EngineRunnable.decode(EngineRunnable.java:101)
        at com.bumptech.glide.load.engine.EngineRunnable.run(EngineRunnable.java:58)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
        at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:52)

Obviously Glide tries to get the image from the wrong place.

I would appreciate if someone point me on how to load a photo with "content://" URIs.

like image 599
Ahmed I. Khalil Avatar asked Apr 03 '15 19:04

Ahmed I. Khalil


2 Answers

You need to create a custom loader that uses a ContentResolver. In Picasso for example this works because there is already a custom request handler that uses a ContentResolver.

I created one custom Glide loader for contacts for my internal use that you can take as reference.

like image 134
lujop Avatar answered Sep 23 '22 07:09

lujop


Seems that Glide doesn't handle content photos Uri automatically.

So I've solved my issue using an RxJava approach.

Here is a method that emits a bitmap (Please notice the scheduler as it is important to not lag the scrolling performance)

private Observable<Bitmap> _getConvertInputStreamToBitmapObservable(ContentResolver cr,
                                                                    Uri contactUri) {
    return Observable.create(new Observable.OnSubscribe<Bitmap>() {
        @Override
        public void call(Subscriber<? super Bitmap> subscriber) {
            InputStream inputStream =
                    ContactsContract.Contacts.openContactPhotoInputStream(cr, contactUri);
            if (inputStream != null) {
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                subscriber.onNext(bitmap);
            }
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}

And here is the client code that uses the method (Please notice the unsubscribing as it is important in recycling).

       if (holder.bitmapSubscription != null) {
            holder.bitmapSubscription.unsubscribe();
        }

        holder.bitmapSubscription = _getConvertInputStreamToBitmapObservable(context.getContentResolver(),
                contactUri)
                .subscribe(holder.userImg::setImageBitmap);
like image 32
Ahmed I. Khalil Avatar answered Sep 19 '22 07:09

Ahmed I. Khalil