Load image and set it when it's finish loading - java

I have an AsyncTask that gets a URL as a parameter, and returns a Bitmap of an image from that URL when it finishes. When I start the activity, I want to show a text (instead of the image) saying "loading...", run the ImageFetcher in the background, and when it finishes, set the image to the ImageView.
The problem is, if I run:
ivPoster.setImageBitmap(imgFetcher.execute(m.getPosterUrl()).get());
It doesn't load the entire activity until the image is loaded. It skips frames.
So I set an on finish listener on the task, that returns the bitmap, and tried to set the image after the bitmap is retrieved:
imgFetcher.setOnFinishListener(new OnTaskFinished() {
#Override
public void onFinish(Bitmap bm) {
// hide the loading image text
tvLoading.setVisibility(View.INVISIBLE);
// place the image
ivPoster.setImageBitmap(bm);
}
});
imgFetcher.execute(m.getPosterUrl());
Yet it still skips frames and 'does too much work on the main thread'.
How can I prevent the frame skipping?

You can instead utilize the UI thread in AsyncTask. If you run the code in that thread to load the image, the rest of the program will not have to wait.
Use this documentation for more insight. You can use either the onPostExecute() method or onProgressUpdate() method instead of causing wait in the background thread.
The main thread is the same as the UI thread. You should be using that to make changes in your UI. That is so that your application does not wait for graphics to load before executing background code, instead doing them simultaneously. In order to use the ImageView from AsyncTask, you can make the ImageView global if the AsyncTask is a subclass and instantiate before execution. Otherwise, pass it as a parameter to the AsyncTask.

private class ImageDownloaderTask extends AsyncTask<String, Void, Bitmap> {
ImageView mImageView;
String mUrl;
public ImageDownloaderTask(ImageView imageview, String url) {
this.mImageView = imageview;
this.mUrl = url;
}
#Override
protected Bitmap doInBackground(String... params) {
//Download here
}
#Override
// Once the image is downloaded, associate it to the imageView
protected void onPostExecute(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}
Hope the code snippet helps

You can think about Picasso lib: http://square.github.io/picasso/
or
Universal Image Loader: https://github.com/nostra13/Android-Universal-Image-Loader

Related

When does image.setImageResource() set the image resource inside a function?

Goal: To click on an image in an app and get it to fade out to make a different image appear.
My Method: To make the 1st image fade away after 2000ms and AFTER THAT change the image resource of the 1st image to the 2nd image to make the 2nd image appear
I have a correct solution which was provided by my instructor, so I dont want any correct solution for this. What i want to know is why is my solution not working, i.e why is setImageResource() setting the Image1 to Image 2 at the beginning despite calling it at the end
This is the fade function i have created which the image1 goes to when it is clicked
public void fade(View view){
ImageView image1 = findViewById(R.id.image1);
image1.animate().alpha(0f).setDuration(2000);
image1.setImageResource(R.drawable.cat2);
}
Actual Output: Image 1 changes to Image 2 as soon as I click it and then Image 2 fades away
Problem: Inspite of calling setImageResource() at the end of the code, it actually sets the image resource at the beginning
You are never telling image1.setImageResource(R.drawable.cat2); wait for 2000 millisecond and execute, So image2 appears as soon as you click it.
Solution:
Call image1.setImageResource(R.drawable.cat2); After 2000ms
new Handler().postDelayed(() -> {
image1.setImageResource(R.drawable.cat2);
}, 2000);
This may help.
The animation is asynchronous in your code - it doesn't block/wait, but starts the animation (or rather, queues the animation to be started) and then immediately executes the next line, which sets the image. If you want to update your image once the animation is complete, you can use withEndAction and supply a callback.
image1.animate()
.alpha(0f)
.setDuration(2000)
.withEndAction(new Runnable() {
#Override
public void run() {
image1.setImageResource(R.drawable.cat2);
}
})
.start();
I think this will be help to you:
Fade In Fade Out Android Animation in Java
so use in onClickListener like this:
image1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
image1.setVisibility(View.GONE);
//Animation...
image2.setVisibility(View.VISIBLE);
}
});

How to download images from the Internet and set them as background in runtime multiple times?

I have such task: need to download images from the internet and set them as view's background every 15 minutes (user sets the period).
I have done something like that:
I have JobService, it downloads images and saves them as files to created directory. After it send broadcast, receiver takes it and sets file names to it's listener. Listener - my class LauncherApplication extends Application, it is created before all activities, I save it's instance and thus I can load images from files in every part of program.I do it with such AsyncTask, execute it if necessary in OnResume() :
public class BackgroundImageAsyncChanger extends AsyncTask<String, Void ,Drawable> {
private int pictureNumber;
private View backgroundView;
private Context context;
public BackgroundImageAsyncChanger(View backgroundView, Context context, int pictureNumber) {
this.backgroundView = backgroundView;
this.context = context;
this.pictureNumber = pictureNumber;
}
#Override
protected Drawable doInBackground(String ... imageFilesNames) {
final int index = pictureNumber;
final Bitmap bitmap = ImageFileOperator.getInstance().loadImage(context, imageFilesNames[index]);
final Drawable drawable = new BitmapDrawable(context.getResources(), bitmap);
return drawable;
}
#Override
protected void onPostExecute(Drawable backgroundImage) {
backgroundView.setBackground(backgroundImage);
}
}
And so there is the problem. It's takes time to download images from the Internet, and when they are downloaded after the Activity/Fragment OnResume() , it doesn't change background.
How I can implement it better?
Thanks every one for answers!
Its better from downloading the image. Use Picasso or Glide
picasso is simple to use
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(imageView);
Glide
Glide.with(mContext).load(imgUrl)
.thumbnail(0.5f)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);
in both the case you not need to worry about downloading the image.As soon as it get load it automatically project on image view. And automatically cache management.
/*********************************************************/
since every 15 min your job scheduler take url from server or whatever so suppose you have a function call
private void jobScheduler(){
new url generates here
call the function to load image and send the url as paramater
loadImages(url);
}
here you load the url in same pitcure again and again after every 15 min
private void loadImages(String url){
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(imageView);
}
Downloading every image can lead to memory leak and its not a good idea.
You can use Glide
Here is the working example:
Glide.with(context)
.load(imageUrl) // or URI/path
.placeholder(placeholder)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.priority(Priority.IMMEDIATE)
.error(placeholder)
.skipMemoryCache(false)
.dontAnimate()
.listener(listener) // you can skip this if do not want to handle callback
.into(imageView); //imageview to set thumbnail to.
Hope it will help you
Instead of downloading image,
you can directly load image using third party like picasso/glide.
Picasso
Picasso.with(mContext)
.load(imageUrl)
.placeholder(R.drawable.img_placeholder)
.error(R.drawable.img_error)
.into(mImageView);
Glide
Glide.with(mContext)
.load(imageUrl)
.thumbnail(0.5f)
.crossFade()
.skipMemoryCache(false)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.listener(mImagelistener)//optional
into(mImageView);
To upgrade images every specific interval,
You can set repeating alarm to send specific broadcast at some interval.
refer: Set Repeating Alarm Every Day at Specific time In Android
or
you can timer/handler class to get event on specific interval.
(Use based on your app structure)
I have developed a similar service to configure wallpapers, the schedule task is managing by a "job service"
MyService myService;
Handler myHandler = new Handler(){
#Override
public void handleMessage(Message msg){
myService = (MyService) msg.obj;
myService.setUICallback(YourActivity.this);
}
};
myServiceComponent = new ComponentName(this, MyService.class);
settings:
JobInfo.Builder builder = new JobInfo.Builder(0, myServiceComponent);
//builder.setRequiresCharging(true);
//builder.setRequiresDeviceIdle(true);
builder.setExtras(bundle);//if you need
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);//only wifi
builder.setPeriodic(900000);//15 min, dont try set less
builder.setPersisted(true);
myService.scheduleJob(builder.build());
and tasks in a jobservice class
public class MyService extends JobService{}
check this tutorial for jobservice
spam:you can see de live project here

Long wait when starting new activity in Android

I have two activities in my Android app.
1) A list which shows items
If the user clicks on one item it opens activity 2
2) Shows a big image of the item
Now, when I click on an item and thus start the second activity there are a few seconds which the app needs to start the activity. (I suspect because of the image it needs to load). This completely destroys the flow of the use case.
What is the best practice to deal with this?
Loading Bitmaps on Main UiThread takes time so you have to load your bitmaps off the Ui Thread. Use the Universal Image Loader for loading/caching the bitmaps. See the link https://github.com/nostra13/Android-Universal-Image-Loader
ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance
// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view
// which implements ImageAware interface)
imageLoader.displayImage(imageUri, imageView);
Hope this helps.
In Second Activity use new Thread.. like below
new Thread(new Runnable() {
#Override
public void run() {
//here put your code
runOnUiThread(new Runnable() {
#Override
public void run() {
//here set your image.
}
});
}
}).start();

Android ListView freezes while loading data

i am using a custom listview with images in my app
and loading all data from a json url.
i have created a onscrollistener()
which automatically add data below the current data when user scrolls to the bottom of the listview.
But when my data is loading whole listview freezes for 2-3 sec.
I dont know whats wrong??
here is my code for AsyncTask
private class BackgroundLoadMore extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
// Showing progress dialog before sending http request
}
protected Void doInBackground(Void... unused) {
runOnUiThread(new Runnable() {
public void run() {
LoadData();
list.setOnScrollListener(new EndlessScrollListener());
}
});
return (null);
}
protected void onPostExecute(Void unused) {
// On completing background task
// closing progress dialog etc,.
}
You must be fetching the json data from url in main UI thread. This blocks the UI from being updated by system, and hence the freeze. Use AsyncTask to do such network tasks in background.
LoadData() should be called in a background thread, which is asynctask's doInBackground(). Your call runOnUIThread puts it back on the UI thread, and that you dont want. remove the runOnUIThread call from asynctask.
protected Void doInBackground(Void... unused) {
LoadData();
return (null);
}
protected void onPostExecute(Void unused) {
// On completing background task
// closing progress dialog etc,.
list.setOnScrollListener(new EndlessScrollListener());
}
Move LoadData(); out of
runOnUiThread(new Runnable() {
public void run() {}
};
doInBackground is performing in the worker thread, but in it you use runOnUiThread wich start a UI therad operations.
You have to load all the data from net in background thread and then in postExecute update your listview
You are probably loading your data inside the UI thread.
Since operations such as loading JSON data from the internet are slow (from 0.5-10 seconds is typical) then if you do that inside the main thread of your app, the user interface will stop responding for this time. You should use a Thread or AsyncTask to load the JSON data asynchronously and so keep the UI thread free to respond to user input (such as scrolling the list).
My suggestion is that you use an AsyncTask to load the data.
Here are some links:
AsyncTask documentation
AsyncTask example
See the accepted answer for this question to see an implementation
Edit
Put list.setOnScrollListener(new EndlessScrollListener()); and list.notifyDatasetChanged(); inside onPostExcecute();

runOnUiThread inside a View

I'm making a custom ImageView . One of the methods is to load an image from a URL. And I want to retrieve the Bitmap in a Thread and load the bitmap in the UI thread.
How can I make a runOnUIThread() call for painting the bitmap?
Is there some kind of built in function? Or should I create a Handler in the constructor and use it for running runnables in the UI thread?
Download the Image via AsyncTask and set to your view in its onPostExecute method
OR
From a separate image downloading thread use the post method of View which will always run its Runnable on UI-thread:
yourImageView.post(new Runnable() {
#Override
public void run() {
// set the downloaded image here
}
});
You can do something like this:
new Thread(new Runnable() {
public void run() {
final Bitmap bm = getBitmapFromURL(myStation.getStation().imageURL);
((Activity) context).runOnUiThread(new Runnable() {
public void run() {
icon.setImageBitmap(bm);
}
});
}
}).start();
This will work outside of an activity, like in a ListAdapter.
Create a class that extends from AsyncTask. Pass the ImageView in the constructor. In the doInBackground method, download the image. In the postExecute method, set the image to the ImageView.

Categories

Resources