Android:Loading an Image from the Web with Asynctask

Android : Loading an image from the Web with Asynctask

If there is no good reason to download the image yourself then I would recommend to use Picasso.

Picasso saves you all the problems with downloading, setting and caching images.
The whole code needed for a simple example is:

Picasso.with(context).load(url).into(imageView);

If you really want to do everything yourself use my older answer below.


If the image is not that big you can just use an anonymous class for the async task.
This would like this:

ImageView mChart = (ImageView) findViewById(R.id.imageview);
String URL = "http://www...anything ...";

mChart.setTag(URL);
new DownloadImageTask.execute(mChart);

The Task class:

public class DownloadImagesTask extends AsyncTask<ImageView, Void, Bitmap> {

ImageView imageView = null;

@Override
protected Bitmap doInBackground(ImageView... imageViews) {
this.imageView = imageViews[0];
return download_Image((String)imageView.getTag());
}

@Override
protected void onPostExecute(Bitmap result) {
imageView.setImageBitmap(result);
}


private Bitmap download_Image(String url) {
...
}

Hiding the URL in the tag is a bit tricky but it looks nicer in the calling class if you have a lot of imageviews that you want to fill this way. It also helps if you are using the ImageView inside a ListView and you want to know if the ImageView was recycled during the download of the image.

I wrote if you Image is not that big because this will result in the task having a implicit pointer to the underlying activity causing the garbage collector to hold the whole activity in memory until the task is finished. If the user moves to another screen of your app while the bitmap is downloading the memory can't be freed and it may make your app and the whole system slower.

Loading Image using AsyncTask

"the app freezes" - This is because you are downloading the images on the event thread or UI Thread. You should never do that. All blocking operations,long running operations, network operations, should be run on a separate thread. Yes you can use asynctask to do the image loading which should fix the issue.

Two options you can do to solve the issue is

  1. Use WebImageView from droid fu library at http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
    WebImageView uses caching as well so you dont need to download images again which you have already downloaded. Downloading images are expensive and consume data.
    I used WebImageView and was able to load images in list. It took me just about 20 mins to get it all working, so you know its easy integrating it.

  2. Second option is to use async task . Please check Android : Loading an image from the Web with Asynctask . There are lot more info in stackoverflow regarding how to do this.

Any time your UI hangs, you should have a creepy feeling, that you are doing something on the UI thread.

How to load multiple image in AsyncTask

Ok assuming then you for some reason want to fetch the images one by one and in sequence, as opposed to in parallel, and assuming you have your URLs in a list, array etc, modify the tutorial example so that onPostExecute calls a method in your activity, either defined in a callback interface or on your class itself, and for each iteration pick one element from the list and start a new LoadImage job whenever the previous one is complete.

Example (untested) code:

public class MainActivity extends Activity {
Button load_img;
ImageView img;
Bitmap bitmap;
ProgressDialog pDialog;
private List<String> mURLs = new LinkedList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
load_img = (Button)findViewById(R.id.load);
img = (ImageView)findViewById(R.id.img);
load_img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
mURLs.add("http://www.learn2crack.com/wp-content/uploads/2014/04/node-cover-720x340.png");
mURLs.add("some-other-URL");

loadNext();
}
});

private void loadNext() {
String url = mURLs.remove();
if (url != null) {
new LoadImage().execute(url);
}
}
}
private class LoadImage extends AsyncTask<String, String, Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Loading Image ....");
pDialog.show();
}
protected Bitmap doInBackground(String... args) {
try {
bitmap = BitmapFactory.decodeStream((InputStream)new URL(args[0]).getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
protected void onPostExecute(Bitmap image) {
if(image != null){
img.setImageBitmap(image);
pDialog.dismiss();
}else{
pDialog.dismiss();
Toast.makeText(MainActivity.this, "Image Does Not exist or Network Error", Toast.LENGTH_SHORT).show();
}

loadNext();
}
}
}

In this example I set the image onto the same ImageView repeatedly which obviously makes no sense. You obviously have to keep track of which image goes onto which imageview by either sending the imageview as an argument to the task, or keep the imageviews (or their R.id.xxx ID's and call findById accordingly) in an array as well, or keep a counter, or.... There are a million ways to solve this.

Another approach is to send the array to the AsyncTask and have doInBackground simply loop over the array with a for-loop or similar.

Note however that a better approach might be to actually parallelize the tasks so that you make sure to utilize your available network bandwidth fully to fetch the images in parallel.

Unable to load image from URL by using async task

Picasso allows for hassle-free image loading in your application—often in one line of code!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Many common pitfalls of image loading on Android are handled automatically by Picasso

  • Handling ImageView recycling and download cancelation in an adapter.
  • Complex image transformations with minimal memory use.
  • Automatic memory and disk caching.

Sample Image

Loading Images to Textview with AsyncTask

Ok I am stupid... I solved it!

I forgot that I only need the AsyncTask if I load images from the internet. For local images I don't need that.

Solution for the interested:

ImageGetter imgGetter = new ImageGetter() {
@Override
public Drawable getDrawable(String source) {
String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath();
Drawable d = Drawable.createFromPath(sdcard+source);
d.setBounds(0, 0, 0 + (int)(d.getIntrinsicWidth()), 0
+ (int) (d.getIntrinsicHeight()));
return d;
}
};
Spanned htmlSpan = Html.fromHtml(textAndImage, imgGetter, null);
textView.setText(htmlSpan);

I wanna learn how to load images in Asynctask way and load those in listViewAdapter

If I were you I would use that list adapter but within it use the picasso library to load the image. Picasso does not load images on the UI thread. That is why you are receiving this error. After adding the library, try making your getView() like so:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

if(convertView == null) {
convertView = inflater.inflate(R.layout.item_pic, null);
holder = new ViewHolder();
holder.imageView = (ImageView) convertView.findViewById(R.id.img_pic);
holder.textView = (TextView) convertView.findViewById(R.id.txt_pic);
convertView.setTag(holder);

}else {
holder = (ViewHolder) convertView.getTag();
}
int resID = (Integer) list.get(position).get("image");
String text = (String) list.get(position).get("text");
//Picasso code
Picasso.Builder builder = new Picasso.Builder(context);
Picasso picasso = builder.build();
picasso.load(resID).into(holder.imageView);
//End Picasso code
holder.textView.setText(text);
notifyDataSetChanged();
return convertView;
}

Download images with AsyncTask

You never called onProgressUpdate during your doInBackGround(...). Please note that running multiple instances of AsyncTask is a bad idea. Here is what I suggest:

if(isSyncSuccess){
SetConstant.IMAGE_EXIST=1;
pDialog=new ProgressDialog(GalleryScreen.this);
pDialog.setMessage("Downloading file. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setProgress(0);
pDialog.setMax(contentId.length);
pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pDialog.setCancelable(true);

new DownloadFile().execute();
}

private class DownloadFiles extends AsyncTask<String, Integer, String> {
@Override
protected String doInBackground(String... sUrl) {
Bitmap bm;
InputStream in;

if (contentId.length > 0) {
for (int i = 0; i < contentId.length; i++) {
if (helper.databaseChecking(useremail, contentId[i])) {
contentdownload = i;
SetConstant.CONTENT_ID = contentId[i];

String URL = SetConstant.URL_DOWNLOAD_CONTENT + contentId[i];
//YOUR INTRESTING LOOP HERE.
publishProgress(30);
//SOME INTRESTING NUMBER FOR PROGRESS UPDATE
}
}

try {
in = new java.net.URL(sUrl[0]).openStream();
bm = BitmapFactory.decodeStream(new PatchInputStream(in));
File storage = new File(Environment.getExternalStorageDirectory() + File.separator + "/Image/");
Log.i(TAG, "storage:" + storage);
Log.i(TAG, "storage:" + storage.getAbsolutePath());
if (!storage.exists()) {
storage.mkdirs();

}
String FileName = "/" + SetConstant.CONTENT_ID + ".jpg";
FileOutputStream fos = new FileOutputStream(storage + FileName);
bm.compress(Bitmap.CompressFormat.JPEG, 85, fos);

String filepath = storage + FileName;
File filecheck = new File(filepath);
long fileSize = filecheck.length();
fos.flush();
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}

return null;
}

@Override
protected void onPreExecute () {
super.onPreExecute();
pDialog.show();
}

@Override
protected void onProgressUpdate (Integer...progress){
super.onProgressUpdate(progress);
pDialog.setProgress(progress[0]);
}

protected void onPostExecute (String result){
super.onPostExecute(result);
pDialog.dismiss();
}
}
}

Of course this code don't run and you need to fix the scopes. But what I am trying to suggest is that your loop should be in doInBackGround(...), you should only have 1 instance of AsyncTask at given time for this case, and call the onProgressUpdate().



Related Topics



Leave a reply



Submit