About Picasso Load picture Callback no implementation

About Picasso Load picture Callback no implementation

Background problem

Code is as follows, Target Callback callback or sometimes not performed.

https://github.com/square/picasso/issues/352

The first: the use of Target

Picasso.get().load(URL).into(new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        Log.i(TAG, "onBitmapLoaded: " + from);
    }

    @Override
    public void onBitmapFailed(Exception e, Drawable errorDrawable) {
        Log.e(TAG, "onBitmapFailed");
    }

    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {
    }
});

The second: Use Callback

ImageView imageView = new ImageView(this);
Picasso.get().load(URL).into(imageView, new Callback() {
    @Override
    public void onSuccess() {
        Log.i(TAG, "onSuccess: ");
    }

    @Override
    public void onError(Exception e) {
        Log.e(TAG, "onError" );
    }
});

The above code, often used in the pre-loaded picture of the business.

problem causes

For such a sporadic problem, the first response should be to hold a reference question. Sure enough, the above problem is a weak reference questions: WeakReference.
Source derivation:

// 1.先看into方法:RequestCreator.java
public void into(@NonNull Target target) {
    // ...
    Action action =
        new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
            requestKey, tag, errorResId);
    picasso.enqueueAndSubmit(action);
}

// 2.跟到Action:TargetAction.java
final class TargetAction extends Action<Target> {

  TargetAction(Picasso picasso, Target target, Request data, int memoryPolicy, int networkPolicy,
      Drawable errorDrawable, String key, Object tag, int errorResId) {
    // target被传到了super构造器
    super(picasso, target, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key, tag,
        false);
  }

  @Override 
  void complete(Bitmap result, Picasso.LoadedFrom from) {
    if (result == null) {
      throw new AssertionError(
          String.format("Attempted to complete action with no result!\n%s", this));
    }
    Target target = getTarget();
    if (target != null) { // 这一句判断很关键
      target.onBitmapLoaded(result, from);
      if (result.isRecycled()) {
        throw new IllegalStateException("Target callback must not recycle bitmap!");
      }
    }
  }

  @Override 
  void error(Exception e) {
    Target target = getTarget();
    if (target != null) { // 这一句判断很关键
      if (errorResId != 0) {
        target.onBitmapFailed(e, picasso.context.getResources().getDrawable(errorResId));
      } else {
        target.onBitmapFailed(e, errorDrawable);
      }
    }
  }
}

// 3.往上跟到Action的构造方法:Action.java
Action(Picasso picasso, T target, Request request, int memoryPolicy, int networkPolicy,
    int errorResId, Drawable errorDrawable, String key, Object tag, boolean noFade) {
// ...
this.target =
    target == null ? null : new RequestWeakReference<>(this, target, picasso.referenceQueue);
// ...
}

There can be seen here, if this.targetthis phantom reference, if gc is recovered in time, there will not be a natural correction.

Scene reproduction

The following code simulates nervous system memory when the gc process, so that even now the issue has become necessary now, or great probability.

public void preloadImage() {
    Picasso.get().load(URL).into(new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            Log.i(TAG, "onBitmapLoaded: " + from);
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {
            Log.e(TAG, "onBitmapFailed");
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
        }
    });

    for (int i = 0; i < 1000; i++) {
        double[] b = new double[1000000];
    }
    System.gc();
}

Solutions

It can be considered by reference blessing, not if references destroyed. There are many ways, where you can consider the use of anonymous inner classes to extend the life cycle of variables.

The first: the use of Target

public void preloadImage() {
    Log.d(TAG, "preloadImage: preloadImage.");
    class Ref {
        private Target t;
    }
    final Ref ref = new Ref();
    ref.t = new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            Log.i(TAG, "preloadImage.onBitmapLoaded: " + from + ref.hashCode());
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {
            Log.e(TAG, "preloadImage.onBitmapFailed" + ref.hashCode());
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
        }

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            Log.e(TAG, "target.finalize!");
        }
    };
    Picasso.get().load(URL).into(ref.t);
}

The second: Use Callback

public void preloadImage() {
    Log.d(TAG, "preloadImage: start.");
    final ImageView imageView = new ImageView(this);
    Picasso.get().load(URL).into(imageView, new Callback() {
        @Override
        public void onSuccess() {
            Log.i(TAG, "preloadImage.onSuccess: " + imageView.hashCode());
        }

        @Override
        public void onError(Exception e) {
            Log.e(TAG, "preloadImage.onError" + imageView.hashCode());
        }

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            Log.e(TAG, "callback.finalize!");
        }
    });
}

the above.

Guess you like

Origin www.cnblogs.com/chavin/p/11420394.html