I'm working on movies Android app which get list of movies from an API which provides a poster path for all movies.
I want to get the image as Bitmap from the image's URL to save it as a Bitmap variable in the model class. I want to save the image as blob in the DB to retrieve it directly without redownloading it each time the user opens the app. Is that possible?
I want to do something like this, but it always returns null.
private Bitmap posterBitmap;
public void setPosterBitmap () {
Picasso.get().load(POSTERS_URL).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
posterBitmap = bitmap; // I don't want to set it to an Image view here
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
});
}
Thanks in advance.
new Thread(() -> {
try {
Bitmap mBitmap = Picasso.get().load(link).get();
} catch (Exception e) {
Log.e(""+e);
}
}).start();
By using
implementation 'com.squareup.picasso:picasso:2.71828'
This code is working for me:
...
private static final String TAG = MainActivity.class.getName();
private Target mTarget;
...
mTarget = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
if (bitmap == null) {
Log.w(TAG, "Null");
} else {
Log.i(TAG, "Worked");
}
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
Log.w(TAG, "failed");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.i(TAG, "Prepare");
}
};
// Small image loads without resize
// Picasso.get().load("http://www.theretirementmanifesto.com/wp-content/uploads/2016/08/Yoda-free-clip-art-680x410.jpg").into(mTarget);
// Mega high res out of memory image
Picasso.get().load("https://upload.wikimedia.org/wikipedia/commons" +
"/5/5e/M104_ngc4594_sombrero_galaxy_hi-res.jpg").
resize(100, 100).into(mTarget);
Also I'm assuming that the following line is in the manifest:
<uses-permission android:name="android.permission.INTERNET" />
Using this version of Picasso:
implementation 'com.squareup.picasso:picasso:2.71828'
Also it may be worth declaring the Target as a member variable due to issues Picaso has arising from 'weak references'. You will have to research this, but I believe it may be unsafe to declare the Target as an anonymous inner class.
Also it may be necessary to call resize(x, y) to prevent an out of memory situation depending on the image sizes and whether you control their source.
UPDATE:
The project won't work as written because it is using an synchronous solution, but you're making an asynchronous call:
holder.moviePosterIV.setImageBitmap(movie.getPosterBitmap());
The code:
public Bitmap getPosterBitmap() {
target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
posterBitmap = bitmap;
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
return posterBitmap;
}
It cannot be done like this. In a nut shell, the Target is going to be called in the future when the image has been downloaded. But the code is being written as if the image is ready immediately.
It is a synchronous solution to an asynchronous problem. In synchronous programming we write 1 line after the other then return the result when the data is ready.
If we wrote it synchronously:
f() {
image = getImage(url) // the program could be blocked here for minutes
return image
}
So instead we do it asynchronously:
f() {
getImageInTheFuture(url, imageReadyFunc); // call imageReadyFunc when it is finally downloaded
}
imageReadyFunc(image) {
setTheImage();
}
The asynchronous solution prevents the app from blocking, but it is also a real pain because we can no longer use a 'return' statement. Instead we have to break the code up into 2 sections. Code that we can run before the image is available. Code that we can run after the image is available.
But under the hood Picasso is doing all of this work for you. I'd really advise against trying to manage the bitmaps directly. In the bad old days of Android before Picasso, Glide, etc. apps used to routinely crash and run out of memory trying to manage their own bitmaps. It is technically difficult to do without causing memory leaks and running out of memory.
Hope that makes sense...
Related
Image
I want to check which languages are downloaded yet so that I can show or hide this image icon. (Mlkit translate)
I want the source code of how to do this.
You can use below codes to check whether the model is downloaded or not:
DownloadConditions conditions = new DownloadConditions.Builder()
.requireWifi()
.build();
englishGermanTranslator.downloadModelIfNeeded(conditions)
.addOnSuccessListener(
new OnSuccessListener() {
#Override
public void onSuccess(Void v) {
// Model downloaded successfully. Okay to start translating.
// (Set a flag, unhide the translation UI, etc.)
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Model couldn’t be downloaded or other internal error.
// ...
}
});
More information here: https://developers.google.com/ml-kit/language/translation/android
I'm using XMLWorker in itextpdf library to convert xHTML to pdf.
In the xHTML content there is some tag with local storage images and images from the Internet.
Eg:
<img src="https://www.w3schools.com/images/w3schools_green.jpg" alt="W3Schools.com" style="width:104px;height:142px;"/>
With the local images, I have implemented ImageProvider to provide the resource root path.
But with these images from the Internet, it cannot be loaded.
I tried to override Image retrieve(String src) method of AbstractImageProvider to load images from the Internet, but I got NetworkOnMainThread exception.
I don't know how to use AsyncTask or any other wars to load online images and return it inside Image retrieve(String src).
I've searched in the Internet and people only use ImageProvider with local images. Any ideas for me?
I don't really understand your question without context. This may be fit with your question.
Create a callback inside your ImageProvider. Then every time AsyncTask (or anything that helps you make a request) gives the response, trigger it.
public class ImageProvider {
private OnImageProviderCallback callback;
public ImageProvider(OnImageProviderCallback callback) {
this.callback = callback;
}
public OnImageProviderCallback getCallback() {
return callback;
}
public void setCallback(OnImageProviderCallback callback) {
this.callback = callback;
}
public interface OnImageProviderCallback {
void onRetrievedImage(Image image);
}
public void retrive() {
new AsyncTask<Void, Void, Image>() {
#Override
protected Image doInBackground(Void... voids) {
// request for image here
If(request.success()) {
return request.getImage();
}else{
// Handle error
return null;
}
}
#Override
protected void onPostExecute(Image image) {
super.onPostExecute(image);
callback.onRetrievedImage(image);
}
}.execute();
}
}
Then in your activity , make it done by calling this
new ImageProvider(new ImageProvider.OnImageProviderCallback() {
#Override
public void onRetrievedImage(Image image) {
// do something with your image
}
});
Until now, I tried to wrap the whole process of conversion from HTML to PDF inside a "big" AsyncTask.
It's work for now, but the code is a bit ugly because it cause code coupling and hard to extend later on for supporting other conversion types.
I have come across a very interisting issue. I am using the bellow code to load bitmaps using picasso:
final Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// loaded bitmap is here (bitmap)
Log.i(TAG, "bitmapLoaded");
imageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.i(TAG, "bitmapFailed");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
imageView.setTag(target);
Picasso.with(this)
.load(photoUrl)
.into(target);
I know a lot of questions have being asked about picasso not loading images due to weak reference but I don't think that's the case, since I have followed the solutions suggested in many topics to reference target like above.
In my program, I use this same code in 3 different classes and in 3 distinct moments. What I have noticed is that whenever I call this method for the first time it doesn't work, but for the next times it works, doesn't matter which of the 3 calls is being used. I can say that because I print different messages to the log from this 3 different methods.
Any thoughts about what is going on or have I missed something?
Thank you in advance.
Try to achieve this with using async approach.
Picasso.with(context).load(URL).into(profile, new Callback() {
#Override
public void onSuccess() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {//Use your "bitmap" here
Bitmap innerBitmap = ((BitmapDrawable) profile.getDrawable()).getBitmap();
}
}, 100);
}
Also you may try to use Glide https://github.com/bumptech/glide
Problem: The problem is Picasso holds a weak reference to the target class and it got GARBAGE COLLECTED.
Solution: Convert it to class field instead of using it as local reference.
Don't know how to do this :
How to change the DecodeFormat on a bitmap that I want to use as a Request :
final BitmapTypeRequest<?> request = Glide.with(context)
.load(uri)
.asBitmap(); // here should be .format(DecodeFormat.PREFER_ARGB_8888)
final SimpleTarget target = new SimpleTarget() {
#Override
public void onResourceReady(Object resource, GlideAnimation glideAnimation) {
memCache.put(nameString, resource);
}
};
// Must be executed on main thread
context.runOnUiThread(new Runnable() {
public void run() {
request.into(target);
}
});
Problem is : .format(DecodeFormat.PREFER_ARGB_8888) return a BitmapRequestBuilder and I need a BitmapTypeRequest
EDIT :
This operation works perfectly :
Glide.with(context)
.load(uri)
.asBitmap()
.format(DecodeFormat.PREFER_ARGB_8888)
.into(imageView);
But as you can see I cache the bitmaps so this method is not good for my use case.
Check this guide. You need to add GlideModule which customize the builder, and then apply it trough the manifest.
The Picasso library allows one to load an image easily like:
Picasso.with(context).load(url).into(imageview);
The API also allows to specify an error image. But what can I do if I want the library to first try three or four different URLs before giving up and displaying the error image? Ideally these images would be tried sequentially, falling back to the next one if the previous wasn't loaded.
Natively there's no API for such functionality. But with some clever coded Picasso.Target you can easily achieve such functionality.
I'll add here a quick hack-untested code that should give you a rought idea on what to look for. You'll have to test and maybe fine tune, but that should be pretty OK.
private static final List<MultiFallBackTarget> TARGETS = new ArrayList<MultiFallBackTarget>();
public static class MultiFallBackTarget implements Picasso.Target {
private WeakReference<ImageView> weakImage;
private List<String> fallbacks;
public MultiFallBackTarget(ImageView image){
weakImage = new WeakReference<>(image);
fallbacks = new ArrayList<String>();
TARGETS.add(this);
}
public void addFallback(String fallbackUrl){
fallbacks.add(fallbackUrl);
}
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from){
removeSelf();
ImageView image = weakImage.get();
if(image == null) return;
image.setImageBitmap(bitmap);
}
public void onBitmapFailed(Drawable errorDrawable){
ImageView image = weakImage.get();
if(image == null) {
removeSelf();
return;
}
if(fallbacks.size() > 0){
String nextUrl = fallbacks.remove(0);
// here you call picasso again
Picasso.with(image.getContext()).load(nextUrl).into(this);
} else {
removeSelf();
}
}
public void onPrepareLoad(Drawable placeHolderDrawable){}
private void removeSelf(){
TARGETS.remove(this);
}
}
Remember that Picasso does not hold strong references to the Target you put inside into(object). That means, internally Picasso uses WeakReference to that.
So that means that you need that self reference in TARGETS to keep reference of all MultiFallBackTarget you create and allow them to self-remove when their job is done.