【问题标题】:Picasso can't load image inside StorageReference's onSuccess methodPicasso 无法在 StorageReference 的 onSuccess 方法中加载图像
【发布时间】:2017-11-20 03:22:03
【问题描述】:

在运行时 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;
}

【问题讨论】:

  • 我遇到了与毕加索类似的问题,请从以下行查看 profView:Picasso.with(mContext).load(task.getResult().getDownloadUrl()) .into(profView); profView 可以用 Fragment 重新创建,Picasso 请求完成。
  • @Wrobel 如果您解决了同样的问题,您能否分享您的代码或将其发布在下面的答案中?

标签: java android firebase picasso firebase-storage


【解决方案1】:

更新 2:

虽然我发布的代码对我有用,但您表示它对您无效。我的测试不使用片段,我不知道您使用的是什么版本的库,现在知道片段是如何添加到布局中的,等等。不同行为的可能原因太多,无法有效调试就这样吧。

作为一项实验,您可以尝试使用 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());
            }
        }
    });

更新:

附加调试显示上传和下载均成功完成。问题在于下载图像的渲染。 documentation for CircleImageView表示从Picasso下载时必须使用noFade()

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

还发现小图像被渲染,而大图像显示为黑色。添加了fit() 以使毕加索调整图像大小。


要检测上传成功和失败,请使用completion listener 而不仅仅是成功侦听器,并测试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();
    }
});

【讨论】:

  • 嗨,鲍勃,感谢您的回答,不幸的是,图像仍未显示,但我可以向您保证,图像已成功上传,因为我可以在 Firebase 存储中看到它。
  • 奇怪。当我下载到 ImageView 时,该代码对我有用。
  • 这个类是对Fragment的扩展,可能和生命周期有关?我真的不知道。
  • @HUSTLE:我更新了我的答案以包括.noFade().fit()。这些对我有用。我会尽快添加解释。
  • 这对我来说没问题。调查剩余的可能原因需要查看更多代码,并且很难使用 cmets 和帖子来完成。我会休息一下。希望其他人可以提供帮助。
【解决方案2】:

de.hdodenhof.circleimageview.CircleImageView 的限制

  • ScaleType 始终为 CENTER_CROP,如果您尝试更改它,您会遇到异常。这是(目前)设计的,因为它非常适合个人资料图片。
  • 不支持启用 adjustViewBounds,因为这需要不受支持的 ScaleType
  • 如果您使用 Picasso 或 Glide 等图像加载库,则需要禁用它们的淡入淡出动画以避免图像混乱。 Picasso 使用 noFade() 选项,Glide 使用 dontAnimate()。如果要保留fadeIn动画,则必须将图像提取到Target中并在接收到Bitmap时自己应用自定义动画。
  • 将 TransitionDrawable 与 CircleImageView 一起使用无法正常工作,并导致图像混乱。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      有可能在这行代码中:

           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)
      

      【讨论】:

      • 它说不允许注释。
      【解决方案5】:

      可能和CircleImageView有冲突。

      尝试使用 ImageView 更改它或将 CircleImageView 定义为 ImageView

      试试:

      ImageView profView = (ImageView) view.findViewById(R.id.profPhoto);
      

      【讨论】:

        猜你喜欢
        • 2016-12-18
        • 1970-01-01
        • 2018-06-02
        • 2020-08-03
        • 1970-01-01
        • 2019-08-14
        • 2017-01-16
        • 2016-04-08
        • 2019-09-18
        相关资源
        最近更新 更多