皮卡索无法在StorageReference的onSuccess方法中加载图像。

12

当在运行时尝试在onStart()方法中使用 Picasso 时,通常会使用控制台中的下载链接从 Firebase 加载图像。

但是,当我尝试在 StorageReference onSuccess 方法中加载图像时,它就无法工作。

这个类正在扩展 Fragment:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == GALLERY_IN && resultCode == Activity.RESULT_OK) {
        isGranted = true;
        String path = FireStorage.retUID() + "/";
        showIndProgress();
        Uri uri = data.getData();

        StorageReference childPathRef = FireStorage.storageRef.child(path + uri.getLastPathSegment());
        childPathRef.putFile(uri)
                .addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) {
                        if(task.isSuccessful()) {
                            Picasso.with(mContext).load(task.getResult().getDownloadUrl())
                                    .into(profView);

                            Picasso.Builder build = new Picasso.Builder(mContext);
                            build.listener(new Picasso.Listener() {
                                @Override
                                public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
                                    Toast.makeText(mContext, "exception\n" + exception.toString(), Toast.LENGTH_SHORT).show();

                                }
                            });
                            progressDialog.dismiss();
                        } else {
                            //failed
                        }

                    }
                });

    }

}

这是另一个类中的我的FirebaseStorage实例:

public static FirebaseStorage storage = FirebaseStorage.getInstance();
public static StorageReference storageRef = 
                           storage.getReferenceFromUrl("gs://myurl.appspot.com/");

清单:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

我的XML布局:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/gcover"
    android:id="@+id/relativeLayout">

    <de.hdodenhof.circleimageview.CircleImageView xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/profPhoto"
        android:clickable="true"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:padding="20dp"
        android:src="@drawable/default_prof"
        android:scaleType="centerCrop"
        app:civ_border_color="@color/trans"
        app:civ_border_width="2dp"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

我的观点初始化:

@Override
public View onCreateView(LayoutInflater inflater,
                         ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_prof, container, false);
    profView = (CircleImageView) view.findViewById(R.id.profPhoto);

    btn1 = (Button) view.findViewById(R.id.btn_1);
    btn2 = (Button) view.findViewById(R.id.btn_2);
    btn3 = (Button) view.findViewById(R.id.btn_3);
    return view;
}

我曾经遇到过与Picasso类似的问题,可以查看以下代码:Picasso.with(mContext).load(task.getResult().getDownloadUrl()) .into(profView);当Picasso请求完成后,可以使用Fragment重新创建profView。 - Wrobel
@Wrobel,如果您已经解决了相同的问题,能否请您分享您的代码或在下面的答案中发布它? - GGWP
5个回答

9

更新2:

虽然我发布的代码对我有效,但你表示它对你无效。我的测试不使用片段,我不知道你正在使用哪个版本的库,也不知道片段是如何添加到布局中的等等。有太多可能导致不同行为的原因,无法在SO上有效地进行调试。

作为一个实验,您可以尝试使用Glide和FirebaseUI来执行下载,而不是Picasso。下面显示了代码,并且对我有效。由于下载是从存储引用而不是URL进行的,因此此方法需要读取存储器的访问权限。您还需要将以下行添加到构建依赖项中:

// FirebaseUI 2.0.1 is the version to use for Firebase SDK version 11.0.1
// SDK/Firebase version compatibility is important.
// See the FirebaseUI docs for a table of compatible versions.
compile 'com.firebaseui:firebase-ui-storage:2.0.1'
compile 'com.github.bumptech.glide:glide:3.8.0'

.

childPathRef.putFile(Uri.fromFile(file))
    .addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) {
            if (task.isSuccessful()) {
                Log.d(TAG, "Upload: SUCCESS");

                Glide.with(mContext)
                    .using(new FirebaseImageLoader())
                    .load(childPathRef)
                    .dontAnimate()
                    .listener(new RequestListener<StorageReference, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, StorageReference model,
                               Target<GlideDrawable> target, boolean isFirstResource) {
                            Log.e(TAG, "Download: FAILED: ", e);
                            return false;
                        }
                        @Override
                        public boolean onResourceReady(GlideDrawable resource,
                               StorageReference model, Target<GlideDrawable> target,
                               boolean isFromMemoryCache, boolean isFirstResource) {
                            Log.d(TAG, "Download: SUCCESS");
                            return false;
                        }
                    })
                    .into(mCircleImageView);
            } else {
                Log.e(TAG, "Upload: FAILED: " + task.getException().getMessage());
            }
        }
    });

更新:

进一步调试显示上传和下载都已经成功完成。问题出现在下载图像的渲染上。 CircleImageView的文档 指出,从Picasso下载时必须使用noFade()

如果您使用像Picasso或Glide这样的图像加载库,则需要禁用它们的淡入淡出动画以避免图像混乱。对于Picasso,请使用noFade()选项;对于Glide,请使用dontAnimate()

同时发现,小图像可以正常渲染,但大图像则会显示为黑色。添加fit()来使Picasso调整图像大小。


要检测上传的成功和失败,请使用完成监听器而不是仅使用成功监听器,并测试task.isSuccessful()。上传可能因为安全规则或无效的StorageReference而失败:

StorageReference childPathRef = Class.storageRef.child(path + uri.getLastPathSegment());
childPathRef.putFile(uri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) {
        if (task.isSuccessful()) {
            Log.d(TAG, "Upload: SUCCESS");
            Picasso.with(mContext)
                .load(task.getResult().getDownloadUrl())
                .noFade()
                .fit()
                .into(profView, new Callback() {
                    @Override
                    public void onSuccess() {
                        Log.d(TAG, "Download: SUCCESS");
                        Toast.makeText(mContext, "download done" , Toast.LENGTH_SHORT).show();                        }

                    @Override
                    public void onError() {
                        Log.d(TAG, "Download: FAILED");
                    }
                });
            Toast.makeText(mContext, "upload done" , Toast.LENGTH_SHORT).show();
        } else {
            Log.e(TAG, "Upload: FAILED: " + task.getException().getMessage());
        }
        progressDialog.dismiss();
    }
});

奇怪。当我下载到ImageView时,代码对我有效。 - Bob Snyder
这个类正在扩展Fragment,也许与生命周期有关?我真的一点都不知道。 - GGWP
1
@HUSTLE:我更新了我的答案,包括.noFade().fit()。这些对我有用。我很快会添加解释。 - Bob Snyder
1
这对我来说显示得很好。要调查剩余的可能原因需要看更多你的代码,而仅凭评论和帖子是很难做到的。我会休息一下,希望其他人能提供帮助。 - Bob Snyder
@PERSISTENCE:我愿意再仔细看看这个问题。已经尝试了简单的修复方法,但没有改善,如果没有看到您的构建文件和更多(或许全部)相关代码,我不认为任何人能够完全理解这个问题。为了得到解决方案,您可能需要在Github或其他代码共享网站上公开您的项目。如果出于隐私或专有原因而无法这样做,那也是可以理解的,但这可能是前进的唯一途径。 - Bob Snyder
显示剩余13条评论

2

de.hdodenhof.circleimageview.CircleImageView 的限制:

  • ScaleType 总是 CENTER_CROP,如果您尝试更改它,则会出现异常。这是(目前)设计如此的原因,因为对于个人资料图像来说完全没问题。
  • 不支持启用 adjustViewBounds,因为这需要一个不受支持的 ScaleType。
  • 如果您使用像 Picasso 或 Glide 这样的图像加载库,您需要禁用它们的淡入淡出动画以避免图像混乱。对于 Picasso,请使用 noFade() 选项,对于 Glide,请使用 dontAnimate()。如果您想保留 fadeIn 动画,则必须将图像获取到 Target 中,并在接收 Bitmap 时自己应用自定义动画。
  • 使用 TransitionDrawable 与 CircleImageView 不起作用,并导致图像混乱。

1

这行代码中有可能出现:

     Picasso.with(mContext).load(task.getResult().getDownloadUrl())
                                .into(profView);    

profView正在使用片段重新创建,Picasso.into(View view)对视图保持了弱引用。

从文档中可以得知:

public void into(android.widget.ImageView target) 异步地将请求填充到指定的ImageView中。注意:该方法会对ImageView实例保持弱引用,并自动支持对象回收。

尝试使用:

public void into(@NotNull ImageView target,
             Callback callback)

它说不允许使用注释。 - GGWP

1

我刚刚从CircleImageView切换到普通的ImageView,然后突然就可以了。


0
也许这是与 CircleImageView 冲突的问题。尝试将其更改为 ImageView 或将 CircleImageView 定义为 ImageView。
尝试:
ImageView profView = (ImageView) view.findViewById(R.id.profPhoto);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接