I'm trying to use an IntentService for processing and uploading images that's running in a different process to have more memory. I'm Using also Picasso to load the Image. When the Image is small the bitmap is loaded successfully and uploaded, however if the image is big the IntentService is terminated before Picasso is done loading It.
Picasso have to run on UIThread
Here is the code.
private void downloadImage(File file) {
final Uri uri = Uri.fromFile(file);
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(new Runnable() {
#Override
public void run() {
Picasso.with(NewImageProcessingService.this).load(uri).transform(new ImageLoadingUtil.DecreaseQualityTransformation(imageQuality)).into(NewImageProcessingService.this);
}
});
}
#Override
protected void onHandleIntent(Intent intent) {
File file = (File) intent.getSerializableExtra(KEY_IMAGE_FILE);
imageQuality = ImagesUtils.IMAGE_QUALITY
.values()[intent.getIntExtra(IMAGE_QUALITY, ImagesUtils.IMAGE_QUALITY.DEFAULT.ordinal())];
downloadImage(file);
}
This question is quite old, but if anyone steps by. The Target is getting garbage collected before it can show the bitmap.
Use it like this
public class BitmapLoader {
public static Target getViewTarget(final OnImageLoadingCompleted onCompleted) {
return new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
onCompleted.imageLoadingCompleted(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
}
}
You need to have a strong reference to the Target so have a field in your IntentService holding it e.g.
private Target viewTarget;
viewTarget = BitmapLoader.getViewTarget(bitmap -> {
// do stuff with the bitmap
});
new Handler(Looper.getMainLooper()).post(() -> Picasso.with(getApplicationContext()).load(object.getImageUrl()).into(viewTarget));
Related
I've got a problem loading bitmaps with Picasso in a loop. I'm loading them in AsyncTasks onPostExecute(). I know that i need global Target variables to prevent them from being collected by GC. Still none of my bitmaps are loaded. Here's my code:
private static Map<Integer, Bitmap> markerBitmaps;
private String[] markerUrls;
private Integer[] catIds;
//some code
private final static List<Target> targets = new ArrayList<Target>();
#Override
protected void onPostExecute(Void result) {
final int[] id = new int[1];
int counter = 0;
for(String s : markerUrls) {
id[0] = catIds[counter];
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
targets.remove(this);
markerBitmaps.put(id[0], bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
targets.remove(this);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
Log.i("BITMAP URL IS:", s);
targets.add(target);
Picasso.with(MapsMenuActivity.this)
.load(s)// Start loading the current target
.into(target);
counter++;
}
Log.i("BITMAPS NUM: ", String.valueOf(markerBitmaps.size()));
}
The size of my markerBitmaps map is always 0.
I have a BackgroundImageActivity that load background image using Picasso. But when I go back to home (onStop() called in BackgroundImageActivity) and go into another instance of this activity, which is supposed to load another background image, but at first 2 seconds, it still shows the image from previous BackgroundImageActivity. Is this some kind of cache?
How I can clear this image so that whenever I go into a new instance of BackgroundImageActivity, i don't see the image from previous one?
public class BackgroundImageActivity extends Activity {
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initBackground();
}
#Override
protected void onStop() {
super.onStop();
Picasso.invalidate(imageUrl, getApplicationContext());
}
private void initBackground() {
...
}
private void setBg(final String imageUrl, final int bg) {
this.imageUrl = imageUrl;
final RequestCreator picassoRequest = Picasso.load(imageUrl, bg).memoryPolicy(MemoryPolicy.NO_CACHE);
targetReference = new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
...
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
...
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
...
}
};
picassoRequest.placeholder(bg).error(bg).into(targetReference);
}
}
Thanks!!!
Use this piece of code while loading the image.
Picasso.with(getContext())
.load(data.get(pos)
.getFeed_thumb_image())
.memoryPolicy(MemoryPolicy.NO_CACHE)
.into(image);
Picasso set the image to ImageView directly without caching in the background. This makes the app lightweight also.
I want before render MainActivity check what all pictures is loaded:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
getBitmapsByURLs(urls);
}
public void getBitmapsByURLs(List<String> urls) {
final List<Target> targets = new ArrayList<>();
for (int i = 0; i < urls.size(); i++) {
final int k = i;
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i("TEMP", "Loaded: " + k);
targets.remove(this);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
targets.remove(this);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.i("TEMP", "Preparing: " + k);
}
};
targets.add(target);
Picasso.with(this)
.load(urls.get(i))
.memoryPolicy(NO_CACHE, NO_STORE)
.into(target);
}
}
How I can check inside onCreate what all pictures is loaded?
If I write while on method onCreate (after call getBitmapsByURLs) then it will be called before all pictures are loaded.
You must be known that when you use
Picasso.with(this)
.load(urls.get(i))
.memoryPolicy(NO_CACHE, NO_STORE)
.into(target);
to load a picture,it is a asynchronized task.First picasso download the picture from internet.After downloading is finished,the picture will be loaded into target.Of course,when downloading,the main thread will never be waiting.Picasso use something like Observer-Subcriber or interface Future to make the main thread informed that downing is over.Above all,no matter what you write after getBitmapsByURLs(urls),it will be called before picasso finishes loading pictures.(Because it usually costs some more time to download pictures and load them into targets).
What's more.This is not a recommended way to do such a time-costing work in onCreate().Because onCreate() is called in main thread.If you do something costs much time here,then you will get an Application Not Responding error.
Good day.I have an google map with cluster manager.Simple one,where i use the cluster to draw markers grouped or not.Anyway i got an method callback from cluster manager which is the Cluster item render one.Inside that callback i am applying custom image to the marker:The user image inside marker.I found Picasso to be the best to handle bitmap loading and at the same time got me lots of headache.I am using Target class from Picasso to initiate the bitmap callbacks:OnPreLoad,OnFail,OnBitmapLoaded.The issue is that on first cluster item render the onBitmapLoaded not called and generally it is never gets called unless it has been touched second time.On first time nothing happens,no callback is triggered except OnPreLoad and by googling i found that the great Picasso holds weak reference to the class.I tried all the examples of the google:Making Target reference strong(getting the initialazation of class out of method and init the class inside my class like the follows)
#Override
protected void onClusterItemRendered(MarkerItem clusterItem, Marker marker) {
mMarker = marker;
mMarkerItem = clusterItem;
Picasso.with(mContext).load(clusterItem.getImageUrl()).transform(new CircleTransformation()).into(target);
}
private Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.d(TAG, "onBitmapLoaded: ");
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.d(TAG, "onBitmapFailed: ");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.d(TAG, "onPrepareLoad: ");
}
};
#Override
protected void onBeforeClusterItemRendered(MarkerItem item, MarkerOptions markerOptions) {
markerOptions.title(item.getTitle());
markerOptions.icon(item.getIcon());
}
At this point i get the same result....Sometimes the bitmap loaded and sometimes not.Mostly not...
Anyway i have tried to implement the interface class to my own class as follows:
public class PicassoMarkerView implements com.squareup.picasso.Target {
private static final String TAG = "MarkerRender";
private Bitmap mMarkerBitmap;
private ClusterManager<MarkerItem> mClusterManager;
private MarkerItem mMarkerItem;
private Marker mMarker;
public PicassoMarkerView() {
}
#Override
public int hashCode() {
return mMarker.hashCode();
}
#Override
public boolean equals(Object o) {
if (o instanceof PicassoMarkerView) {
Marker marker = ((PicassoMarkerView) o).mMarker;
return mMarker.equals(marker);
} else {
return false;
}
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap,
mMarkerBitmap.getWidth() - 15, (int) (mMarkerBitmap.getHeight() / 1.5 - 15),
false);
mMarker.setIcon(BitmapDescriptorFactory.fromBitmap(overlay(mMarkerBitmap, scaledBitmap, 8, 7)));
Log.d(TAG, "onBitmapLoaded: ");
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.d(TAG, "onBitmapFailed: ");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.d(TAG, "onPrepareLoad: ");
}
private Bitmap overlay(Bitmap bitmap1, Bitmap bitmap2, int left, int top) {
Bitmap res = Bitmap.createBitmap(bitmap1.getWidth(), bitmap1.getHeight(),
bitmap1.getConfig());
Canvas canvas = new Canvas(res);
canvas.drawBitmap(bitmap1, new Matrix(), null);
canvas.drawBitmap(bitmap2, left, top, null);
return res;
}
public void setMarkerBitmap(Bitmap markerBitmap) {
this.mMarkerBitmap = markerBitmap;
}
public void setClusterManager(ClusterManager<MarkerItem> clusterManager) {
this.mClusterManager = clusterManager;
}
public void setMarkerItem(MarkerItem markerItem) {
this.mMarkerItem = markerItem;
}
public void setMarker(Marker marker) {
this.mMarker = marker;
}
}
Unfortunatally this is not working either...Same result...So please dear friends can you give me an working example of this?As far as i could google,the issue mostly happens to the user which try to do this inside loop and my onClusterItemRender some sort of loop lets say as it is triggered every time marker is visible to user,so yeah it is triggered several times and as fast as loop so give me some idea please and help me out...
Important to mention that i do not need to use methods from picasso like fetch(),get() as they are not necessary and not fitting the purpose of the app.
I encountered similar issue and holding reference to the target didn't help at all.
The purpose of my project was to use 2 different image downloading api's to show an images gallery and to give the user the ability to choose which api to use.
Beside Picasso I used Glide, and I was amazed by the results, Glide's api worked flawlessly in every aspect wile Picasso gave me hell (that was my first time using Glide, I usually used Picasso so far, seems like today it's gonna change ^^ ).
So my suggestion to you is:
Use glide over Picasso (no such weak reference on their target).
Since I had to use both libraries I ended up using get() in an handler, not sure if it will help you but it solved my problem:
handlerThread = new HandlerThread(HANDLER_THREAD_NAME);
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
#Override
public void run() {
Bitmap bitmap = null;
try {
bitmap = picasso.with(appContext).load(url).get();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bitmap != null) {
//do whatever you wanna do with the picture.
//for me it was using my own cache
imageCaching.cacheImage(imageId, bitmap);
}
}
}
});
I have an async task that download data from webpage using HTTPClient. The problem is while the Picasso is downloading image, the async task must wait for the image downloading to be done.
How could I make the async task run before the image downloading?
I tried this but it doesn't work:
protected Void doInBackground() {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
private Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
//Set the Bitmap into any views if you want.
// Start AsyncTask Here.
}
#Override
public void onBitmapFailed() {
}
}
private void someMethod() {
Picasso.with(this).load("url").into(target);
}