I am trying to download a image file. For some cases the image is so big it is giving OutOfMemoryError in the mid-way. How to deal with this situation?
private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setTitle("Download Image");
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Bitmap doInBackground(String... URL) {
String imageURL = URL[0];
Bitmap bitmap = null;
try {
// Download Image from URL
InputStream input = new java.net.URL(imageURL).openStream();
// Decode Bitmap
bitmap = BitmapFactory.decodeStream(input);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
// Set the bitmap into ImageView
image.setImageBitmap(result);
// Close progressdialog
mProgressDialog.dismiss();
}
}
First of all you need to determine, in what screen or screen part you need to display it. You need to define result sizes (width and height) of container, that will show your image in application. Then, when you receive your image, you need to scale it down to target size and only then show it.
Here is full stack of tutorials how to do it !link!
But I would recomend you use one of 'load images' libraries. Picasso is a good example. Please check it out here
If you don't want to use libraries like Picasso you can use Volley.
Go search for NetworkImageView , maybe it will hep you.There is one tutorial : using-volley-to-download-cache-and-display-bitmaps.
You can take a look at this question too : how-do-i-properly-set-up-volley-to-download-images-from-a-url
And here too : Volley Request
add "android:largeHeap=true" in application tag of manifest file
Related
i want load about 50 image into listview
this is my code for load image from url
class ImageDownloader extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public ImageDownloader(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String url = urls[0];
Bitmap mIcon = null;
try {
InputStream in = new java.net.URL(url).openStream();
mIcon = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
}
return mIcon;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
but image load slow.
and I try use Picasso library, but loading speed slow too
how a better solution to load lot of image from url faster.
sorry for my bad English
thank you for reading
You could try to add this to your android manifest
<application android:hardwareAccelerated="true" ...>
i use this to load videos faster, and it works for me ;) Maybe it'll also work for you
you should try UrlImageViewHelper module ,
download the jar from https://github.com/koush/UrlImageViewHelper ,
add it to your android project .
then a simple command
ImageView imgView = (ImageView) findViewById(R.id.someImage);
UrlImageViewHelper.setUrlDrawable(imgView,your uri);
also works with list adapters when views are reused.
I'm getting this error when trying to retrieve an image from a url using Asynctask.
This is my asynctask:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap result = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
result = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return result;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
if (result != null && !result.isRecycled()) {
result.recycle();
result = null;
}
}
}
If I remove the result.recycle(), the error would be OutofMemoryError.
I'm retrieving multiple images from different url.
How can I do this?
I'm calling the asynctask by:
new DownloadImageTask(imageview[i]).execute(paths.get(i));
Many thanks, :)
You can't recycle here because you still need the bitmap. The problem is that the total amount of memory used by these bitmaps is greater than the total amount of memory available (when added to the memory used by the app already). And because of that, the suggestion 1 person gave to use a library won't help- it won't add memory. Here's a few things you can do:
1)Reduce the memory used by your app. May or may not be possible, look at a heap profiler and see if you have memory leaks.
2)Do not download all the images at once.
3)Rather than downloading them into memory, write it to a file and open each image only when actually needed. This can be combined with an LRUCache to make sure you never use more than a fixed amount of memory.
Use picasa library
ImageView product_image = (ImageView) itemview
.findViewById(R.id.product_image);
Picasso.with(context)
.load(product_order_details.get(position).product_image)
.placeholder(R.drawable.defalutimage).fit().into(product_image);
I am trying to show an image in my app from an URL, but when (only when) the bitmap is showed the app gets way too slow. The app goes OK, but when I load the image it goes extremly slow. Someone can help with this?
So I have a class named ImageDownload which does the download and in my Fragment I have:
new ImageDownload((ImageView) login_image, this.getActivity().getApplicationContext(),"login_image")
.execute(path);
Here is my download Class:
public class ImageDownload extends AsyncTask<String, Void, Bitmap> {
private Context mContext;
private String filename;
ImageView bmImage;
public ImageDownload(ImageView bmImage, Context mContext, String filename) {
this.bmImage = bmImage;
this.mContext = mContext;
this.filename = filename;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in,null,null);
//EDIT:
in.close();
// The isuue is not soved yet
} catch (Exception e) {
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
Then the problem with the size of your ImageBitmap & the RAM size of the tablet. It is taking too much of RAM on loading the ImageBitmap on RAM. You can detect this by looking into the log, how frequent System.gc() is getting called, as the system facing too frequent page misss than page hit, its almost like thrashing problem. I'm sure the system is calling .gc() so frequently and as the System.gc() is called in GUI thread, it is disturbing UI experience.
You should be using Google's Volley library
Use Picasso. It's simple and cool.
I finally found the response. Check it out. it might help you in the future. Thank you to all of you. This works perfectly:
http://www.technotalkative.com/android-load-images-from-web-and-caching/
public class LoadImageActivity extends Activity {
ImageView image_view;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
image_view = (ImageView)findViewById(R.id.imageview);
me m1=new me();
m1.execute("http://wallbase1.org/thumbs/rozne/thumb-499842.jpg");
me m2=new me();
m2.execute( "http://wallbase1.org/thumbs/rozne/thumb-637449.jpg");
me m3=new me();
m3.execute( "http://wallbase1.org/thumbs/rozne/thumb-2509834.jpg");
me m4=new me();
m4.execute( "http://wallbase1.org/thumbs/rozne/thumb-2501884.jpg");
me m5=new me();
m5.execute( "http://wallbase1.org/thumbs/rozne/thumb-2514440.jpg");
};
class me extends AsyncTask<String, Integer, Bitmap> {
Bitmap b1;
// private MainActivity m1;
protected Bitmap doInBackground(String...params) {
// TODO Auto-generated method stub
try {
/* Open a new URL and get the InputStream to load data from it. */
URL aURL = new URL(params[0]);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
/* Buffered is always good for a performance plus. */
BufferedInputStream bis = new BufferedInputStream(is);
/* Decode url-data to a bitmap. */
Bitmap bm = BitmapFactory.decodeStream(bis);
b1=bm;
bis.close();
is.close();
} catch (IOException e)
{
Log.e("DEBUGTAG", "Remote Image Exception", e);
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
image_view.setImageBitmap(b1);
Animation rotation = AnimationUtils.loadAnimation(LoadImageActivity.this, R.anim.rotate);
image_view.startAnimation(rotation);
}
}}
I am trying to show an image from internet by decoding it into bitmap,i want to show multiple images from multiple urls.Is there any better way of implementing it?
The duration of a download depends on a lot of different stuff. You currently spawn 5 AsyncTasks and there is no guarantee that the order of delivery/execution will be the same order you spawned them. It is easily possible that the fifth image might be the first you received and this would result in a totally wrong order. So you should download all images first, possibly with just one AsyncTask. After that and if that succeeded, you should start the animation and switch between the images.
There're several better ways of doing it and all of them are far more complex than your code. But you do have a good start.
This video form Google I/O have some good techniques for image, check around 4:40 https://www.youtube.com/watch?v=gbQb1PVjfqM
It takes different times because they are different images with probably different sizes.
Please post your XML R.anim.rotate code so someone can try to check why the animation is not working.
I'm not really sure what goes wrong with my code or structure. I wanted to use AsyncTask to download images and display out the progress bar at the mean time. But I tried out a few different way of doing it. It still failed and no idea what's wrong with it. My structure flow is
ContentID is a string array that stores the content ID of the Images.
Primary Issue: It managed to download images from the url and store into the phone, but the downloaded images are all the same image. It should be different images, it's not what I expected.
Secondary Issue: The progress bar pop up while the application downloading images, but the progress bar did not update it's progress. It just remains 0% and dismissed after the download completed.
I wanted to know what causes primary and secodary issue as i mentioned. Please leave a comment or answer if you might know what's wrong with my code. Any help will be appreciated.
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);
if (contentId.length>0){
Log.i(TAG, "contentid.length:" +contentId.length);
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];
DownloadFile downloadFile = new DownloadFile();
downloadFile.execute(URL);
}
private class DownloadFile extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... sUrl){
Bitmap bm;
InputStream in;
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();
Log.i(TAG, "bm:" +bm);
Log.i(TAG, "fos:" +fos);
Log.i(TAG, "filesize:" +fileSize);
Log.i(TAG, "filepath:" +filepath);
}
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();
}
}
Edit
Now the application able to download images according and the progress bar is working as well! But I got another issue is how to return error message when the application failed to complete the download. Currently when the application failed to download it will crash. I believed that I should not run it inside the doInBackground side. But where else can I do the checking? Any idea how to return as an error message and request for the user to retry instead of crashing the application?
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().
Primary issue :
SetConstant.CONTENT_ID = contentId[i];
String URL = SetConstant.URL_DOWNLOAD_CONTENT+contentId[i];
Here, you are facing trouble. As #Sofi Software LLC's answer, you are using a global variable, whose value is being changed by the main thread, in another thread.
Secondary Issue :
If you want a progress bar to update, you have to update its value;
it doesn't update itself.
You do need to download the image in AsyncTask (Downloading from URL). Effectively to achieve your functionality, you need to do
Create AsyncTask to download your image (implement download in
doInBackground()), also have a boolean (say isImageDownloaded) to
track if the image is successfully downloaded in postExecute().
Don't forget to also show your progress bar before initiating the
download
Execute your AsyncTask to initiate download
Create extension of android.os.CountDownTimer to countdown a minimum
time
On the method onFinish() check the boolean that you track, if it is
false then you cancel the AsyncTask and throw the toast/dialog that
you intended
Running multipule instance of AsyncTask is not a good idea, so do one after another. You can execute your AsyncTask's on an Executor using executeOnExecutor().To make sure that the threads are running in a serial fashion please use: SERIAL_EXECUTOR.
Following resources may help you #
If you need to download an image, show progress bar and load in a imageview
https://github.com/koush/UrlImageViewHelper
http://developer.aiwgame.com/imageview-show-image-from-url-on-android-4-0.html
http://blog.blundell-apps.com/imageview-with-loading-spinner/
If you need to download multiple files (here, for images) using AsyncTask
Problem with downloading multiple files using AsyncTask
How to get back the task completion status in AsyncTask
Implement Progress Bar for File Download in Android
EDIT:
From http://developer.aiwgame.com/imageview-show-image-from-url-on-android-4-0.html
new DownloadImageTask((ImageView) findViewById(R.id.imageView1))
.execute("http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png"); }
public void onClick(View v) {
startActivity(new Intent(this, IndexActivity.class));
finish();
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
} }
From Image download in an Android ImageView and Progressbar implementation
// note that you could also use other timer related class in Android aside from this CountDownTimer, I prefer this class because I could do something on every interval basis
// tick every 10 secs (or what you think is necessary)
CountDownTimer timer = new CountDownTimer(30000, 10000) {
#Override
public void onFinish() {
// check the boolean, if it is false, throw toast/dialog
}
#Override
public void onTick(long millisUntilFinished) {
// you could alternatively update anything you want every tick of the interval that you specified
}
};
timer.start()
In the following line:
SetConstant.CONTENT_ID = contentId[i];
You're setting a global variable to a value, then you create a string url based on that same value and pass it to the AsyncTask. That executes, and then when it is done downloading, it create a file whose name is based on the global variable SetConstant.CONTENT_ID.
In other words, you are using a global variable, whose value is being changed by the main thread, in another thread. Don't do this, as you will get all kinds of weird problems due to the different threads updating at different times.. Pass in the value or the name of the output file to the AsyncTask. You can do that in a constructor for DownloadFile, and stash the value in a field.
If you want a progress bar to update, you have to update its value; it doesn't update itself. Call AsyncTask.publishProgress during the task (in doInBackground) and implement onProgressUpdate to update the progress dialog.
[EDIT: onProgressUpdate is indeed called in the UI thread.]
First create a separated class which allows you to reach to image address
like following:
public class ImageDownloader extends AsyncTask {
#Override
protected Bitmap doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(inputStream);
return myBitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Then get access to that class (through a method called by a button) by creating an object and execute the Bitmap task like following :
public class MainActivity extends Activity {
ImageView downloadedImg;
public void downloadImage(View view) {
ImageDownloader task = new ImageDownloader();
Bitmap myImage;
try {
myImage = task.execute("YOUR IMAGE ADDRESS ........").get();
downloadedImg.setImageBitmap(myImage);
} catch (Exception e) {
e.printStackTrace();
}
}
Do NOT forget to:
1 - define the imageView in onCreat method ==> downloadedImg = (ImageView) findViewById(R.id.imageView);
2 - to link the method you've created by a button in user interface ==> (public void downloadImage(View view){})
3 - ask for permission in manifest file