I have a listView with ImageViews.
I try to compress the bitmaps with the following code:
public void getImage(final String urlStr, final ImageView toSet) {
// set the tag immediately, to prevent delayed image downloads from
// setting this image.
toSet.setTag(urlStr);
getImage(urlStr, new ImageRepository.ImageRepositoryListener() {
#Override
public void onImageRetrieved(final Drawable drawable) {
if (drawable == null)
return;
toSet.post(new Runnable() {
#Override
public void run() {
// make sure the tag is still the one we set at the
// beginning of this function
if (toSet.getTag() == urlStr) {
toSet.setImageDrawable(drawable);
drawable.setCallback(null);
}
}
});
}
});
}
public class DownloadImageAsyncTask2 extends
AsyncTask<String, Void, Bitmap> {
private final ImageView imageView;
private String imageUrl;
public DownloadImageAsyncTask2(ImageView imageView) {
this.imageView = imageView;
}
#Override
protected void onPreExecute() {
Log.i("DownloadImageAsyncTask", "Starting image download task...");
}
#Override
protected Bitmap doInBackground(String... params) {
imageUrl = params[0];
try {
imageRepository.getImage(imageUrl, imageView);
return BitmapFactory.decodeStream((InputStream) new URL(
imageUrl).getContent());
} catch (IOException e) {
Log.e("DownloadImageAsyncTask", "Error reading bitmap" + e);
downloadingImageUrls.remove(imageUrl);
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
imageCache.put(imageUrl, bitmap);
downloadingImageUrls.remove(imageUrl);
if (bitmap != null
&& ((String) imageView.getTag()).equals(imageUrl)) {
imageView.setImageBitmap(bitmap);
}
}
}
How can I make the image loading time be faster?
(I have tried to downsize the images on the server side, but I want to think what can I improve in the client side).
I use async download task to download the images and a cache layer to persist them.
Here is the code:
Your image loading is slow because:
After downloading and saving images in the cache , the AsyncTask is used to load but it doesn't give the result immediately.
Firstly, it is controlled by the global Thread's pool with the number maximum of thread in concurrence. Sometimes , it begins after finishing the other AsyncTask .
Secondly, the method "onPostExecute" is executed in Main Thread but after finishing all the other messages of Main Thread.
So:
Use AsyncTask only to download and save images in the cache.
Try to check if the expected image exists in the cache before using AsyncTask. If it exists then you display it directly in Main thread. Make sure that the size of expected image fits well in your image view .
In your case , add the code like this:
public void getImage(final String urlStr, final ImageView toSet) {
//get the expected image associated with this url and the size of this image view in the cache
Bitmap bitmap = getExpectedBitmap(urlStr,expectedSize);
if(bitmap != null) {
//if it exists , set it in the image view and finish.
toSet.setImageBitmap(bitmap);
return;
}
// set the tag immediately, to prevent delayed image downloads from
// setting this image.
toSet.setTag(urlStr);
getImage(urlStr, new ImageRepository.ImageRepositoryListener() {
#Override
public void onImageRetrieved(final Drawable drawable) {
if (drawable == null)
return;
toSet.post(new Runnable() {
#Override
public void run() {
// make sure the tag is still the one we set at the
// beginning of this function
if (toSet.getTag() == urlStr) {
toSet.setImageDrawable(drawable);
drawable.setCallback(null);
}
}
});
}
});
}
Related
I am making an application that generates a random image by a url when touching the button and presents it in the imageview and I use picasso and to change the image you have to clear the cache and I would like someone to tell me how I could go back to the previous image, like a back button
Any help is appreciated from the heart
My code to generate a new image:
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String quest1 = "https://proxxcraft.com/";
Picasso.get().load(quest1).memoryPolicy(MemoryPolicy.NO_CACHE).into(memeRandomView);
Picasso.get().isLoggingEnabled();
}
});
you should save the image as a bitmap, save it in an array or some other data structure. I know how to do it with glide but you should check for how to set callbacks to know when the image is loaded.
private void loadImage() {
Picasso.with(this)
.load("https://proxxcraft.com/")
.into(mContentTarget);
}
private Target mContentTarget = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
//save the bitmap in an array so you can use it later.
Imageview.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
This question already has answers here:
android asynctask sending callbacks to ui [duplicate]
(4 answers)
Closed 6 years ago.
Okay, it might be a noob question, but I couldnt find anything to help me. I am loading an BitMap on a ImageView as an Async task, in this class:
class MyNetworkTask extends AsyncTask<URL, Void, Bitmap> {
ImageView tIV;
public MyNetworkTask(ImageView iv){
tIV = iv;
}
#Override
protected Bitmap doInBackground(URL... urls) {
Bitmap networkBitmap = null;
URL networkUrl = urls[0]; //Load the first element
try {
networkBitmap = BitmapFactory.decodeStream(
networkUrl.openConnection().getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
return networkBitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
tIV.setImageBitmap(result);
}
And thats how I call it from my Activity:
new MyNetworkTask(myImageView).execute(photo_url);
But that is going to be async, right? Which means that if right after in my Activity I try to use the BitMap, it will be null.
Is there a loop like a "do when??" that waits for this BitMap, and than do something?
Or is there a way of handling a callback from that Async Class?
If you are speaking of storing the bitmap so you can access it later you should create a public Bitmap bitmap; outside of your AsyncTask then populate it from your AsyncTask.
class MyNetworkTask extends AsyncTask<URL, Void, Bitmap> {
ImageView tIV;
public MyNetworkTask(ImageView iv){
tIV = iv;
}
#Override
protected Bitmap doInBackground(URL... urls) {
Bitmap networkBitmap = null;
URL networkUrl = urls[0]; //Load the first element
try {
networkBitmap = BitmapFactory.decodeStream(
networkUrl.openConnection().getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
return networkBitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
if(result != null){
bitmap = result;
}
tIV.setImageBitmap(result);
}
You can use the pattern observer for that. Check out this link for the implementation http://www.tutorialspoint.com/design_pattern/observer_pattern.htm
What do you mean with "do when"?
I think of something like that:
do{
networkBitmap = BitmapFactory.decodeStream(
networkUrl.openConnection().getInputStream());
}while(networkBitmap==null)
same works with a while loop:
while(networkBitmap==null){
networkBitmap = BitmapFactory.decodeStream(
networkUrl.openConnection().getInputStream());
}
I am working on an app which requires that I download an image after a button press. I was going to use AsyncTask, until I found out that you can only call a particular AsyncTask once. What should I use instead so that I can still use Progress Dialog and whatnot but still call it on button press?
called on button press, passing in an int
class ImageDownloader
extends AsyncTask<Integer, Integer, Bitmap> {
protected void onPreExecute(){
launchDialog();
}
#Override
protected Bitmap doInBackground(Integer... params) {
//TODO Auto-generated method stub
try{
//finding and downloading an image, and passing back the proper bitmap to the onPostExecute
}catch(Exception e){
Log.e("Image", "Failed to load image", e);
}
return null;
}
protected void onProgressUpdate(Integer... params){
}
protected void onPostExecute(Bitmap img){
ImageView iv = (ImageView) findViewById(R.id.imageView);
if(iv!=null && img!=null){
iv.setImageBitmap(img);
new PhotoViewAttacher(iv);
}
closeDialog();
enablebuttons();
}
protected void onCancelled(){
closeDialog();
enablebuttons();
}
}
Thanks in advance!
Just create a new instance of the AsyncTask in your click handler every time and run that (as opposed to executing a single instance over and over).
i have a problem: i implemented an android project which plays a song when i push a button. also it shows in an another view (the app has two fragments) the meta-data of the mp3-file. i mean with meta-data the name of the interpreter, songcover ... i have only one mp3-file in the raw-directory. but when i put an another mp3-file in the raw-directory (only this without changing the code) , the meta-information disappears suddenly. the results are null. these are not longer displayed. when i delete the one mp3-file it displayed again the meta-data. can s.o. tell me why i could not put another mp3-file in the raw-directory? i dont understand it. :(
i changed nothing in the code, only put an another mp3-file. then it does not work.
how can i fix it? thanks in advance
Try something like loading each inside an AsyncTask:
private class LoadImageTask extends AsyncTask<String, Void, Bitmap>{
private ImageView artImage;
public LoadImageTask(ImageView image){
artImage = image;
}
#Override
protected void onPreExecute() {
retriever = new MediaMetadataRetriever();
}
#Override
protected Bitmap doInBackground(String... params) {
retriever.setDataSource(params[0]);
byte[] art = retriever.getEmbeddedPicture();
Bitmap bitmap = null;
if( art != null ){
bitmap = BitmapFactory.decodeByteArray(art, 0, art.length);
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bm) {
if( bm != null ){
artImage.setImageBitmap(bm);
}
else{
artImage.setImageResource(R.drawable.no_image);
}
}
}
In my app, i need to get current wallpaper of the device:
Wallpaper = WallpaperManager.getInstance(getApplicationContext()).peekDrawable();
no, the problem is that this action will cause the UI to lag a bit while it's getting the background, furthermore, i need to set it as my app's background, i've tried this:
//Drawable Wallpaper defined already...
new Thread(new Runnable() {
public void run() {
Wallpaper = WallpaperManager.getInstance(getApplicationContext()).peekDrawable();
}
}).start();
if (Wallpaper == null)
{
//Resources res = getResources();
//Drawable drawable1 = res.getDrawable(R.drawable.bg1);
//getWindow().setBackgroundDrawable(drawable1);
}
else
{
Wallpaper.setAlpha(50);
getWindow().setBackgroundDrawable(Wallpaper);
}
//........
but it's not working, any ideas?
if possible, please give the code, i'm still kinda new to android..
also, is there a better way to do this?
Try the following and see if it helps. I've commented the code for you to expand on (if needed).
private class SetWallpaperTask extends AsyncTask<Void, Void, Void> {
Drawable wallpaperDrawable;
#Override
protected void onPreExecute() {
// Runs on the UI thread
// Do any pre-executing tasks here, for example display a progress bar
Log.d(TAG, "About to set wallpaper...");
}
#Override
protected Void doInBackground(Void... params) {
// Runs on the background thread
WallpaperManager wallpaperManager = WallpaperManager.getInstance
(getApplicationContext());
wallpaperDrawable = wallpaperManager.getDrawable();
}
#Override
protected void onPostExecute(Void res) {
// Runs on the UI thread
// Here you can perform any post-execute tasks, for example remove the
// progress bar (if you set one).
if (wallpaperDrawable != null) {
wallpaperDrawable.setAlpha(50);
getWindow().setBackgroundDrawable(wallpaperDrawable);
Log.d(TAG, "New wallpaper set");
} else {
Log.d(TAG, "Wallpaper was null");
}
}
}
And to execute this (background) task:
SetWallpaperTask t = new SetWallpaperTask();
t.execute();
If you're still stuck, I recommend you go through the SetWallpaperActivity.java example and try to replicate that.