我正在尝试使用 Glide 加载带有 URI“content://com.android.contacts/contacts/295”的联系人照片。
当我使用时
Glide.with(context).load(Uri.parse(contactPhoto).into(imageview)
Glide 给了我一个 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)
显然 Glide 尝试从错误的位置获取图像。
如果有人告诉我如何使用“content://”URI 加载照片,我将不胜感激。
您需要创建一个使用 ContentResolver 的自定义加载程序。 例如,在 Picasso 中,这是可行的,因为已经有一个使用 ContentResolver 的自定义请求处理程序。
我创建了一个自定义的Glide loader 供我内部使用的联系人,您可以作为参考。
所以我使用 RxJava 方法解决了我的问题。
这是一个发出位图的方法(请注意调度程序,因为不要滞后滚动性能很重要)
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());
}
这是使用该方法的客户端代码(请注意取消订阅,因为它在回收中很重要)。
if (holder.bitmapSubscription != null) {
holder.bitmapSubscription.unsubscribe();
}
holder.bitmapSubscription = _getConvertInputStreamToBitmapObservable(context.getContentResolver(),
contactUri)
.subscribe(holder.userImg::setImageBitmap);
ContentResolver
。
ContentResolver contextResolver = context.getContentResolver();
Uri uri = Uri.parse("content://com.android.contacts/contacts/295");
Bitmap thumbnail = null;
Cursor cursor = contentResolver.query(uri, new String[] {ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
try {
if (cursor.moveToFirst()) {
final byte[] thumbnailBytes = cursor.getBlob(0);
if (thumbnailBytes != null) {
thumbnail = BitmapFactory.decodeByteArray(thumbnailBytes, 0, thumbnailBytes.length);
}
}
}
finally {
cursor.close();
}
if (thumbnail != null) {
imageView.setImageBitmap(thumbnail);
}
试试这个。这应该有效。
Uri uri =
ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, new
Long(contactsPojo.getId()));
final Uri displayPhotoUri = Uri.withAppendedPath(uri,
ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
Glide.with(context)
.load(displayPhotoUri)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.fallback(R.mipmap.ic_launcher)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.image);
Glide.with(context)
.load(uri)
.addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
Log.i(TAG, "onLoadFailed: ");
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
Log.i(TAG, "onResourceReady: ");
return false;
}
})
.into(holder.imgProfile);
CONTACT_ID
。然后将这个
CONTACT_ID
与
PHOTO_URI
进行匹配。
//first create a cursor
val photoCursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
photoProjection,
ContactsContract.Contacts._ID + "=?",
arrayOf(contactId),
null
)
//where photoProjection is like so
val photoProjection: Array<String> = arrayOf(
ContactsContract.Contacts.Photo.PHOTO_URI,
ContactsContract.Contacts._ID
)
//now grab the PHOTO_URI, this will only exist if there is a photo
val photo = if (photoCursor?.moveToFirst() == true) {
photoCursor.getString(photoCursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI))
} else {
null
}
//In Glide now you can load the URI directly
Glide.with(this)
.load(uri)
.apply(imageTransform)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(image)
为了捕获该
FileNotFoundException
(这可能会严重影响日志)或用默认图像替换丢失的图像,必须确保该图像存在,在使用Glide传递
Uri
之前。XML 看起来像这样:
<QuickContactBadge
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="center"
app:imageUrl="@{ item.thumbnail }"/>
默认数据绑定组件的伴生对象:
companion object {
val LOG_TAG: String = SomeFragment::class.java.simpleName
/** DataBinding the QuickContactBadge. */
@BindingAdapter("imageUrl")
fun loadImage(imageView: ImageView, uri: Uri?) {
if (uri != null && uriWouldResolve(imageView.context, uri)) {
Glide.with(imageView.context).load(uri).into(imageView)
} else {
// TODO: optionally load default image.
}
}
/** Reduce Log Spam. */
private fun uriWouldResolve(context: Context, uri: Uri): Boolean {
var exists = false
try {
val ins: InputStream? = context.contentResolver.openInputStream(uri)
if (ins?.read()!! > 0) {exists = true}
ins.close()
} catch (e: FileNotFoundException) {
Log.w(LOG_TAG, "file not found: ${e.message}")
}
return exists
}
}