Download images with AsyncTask - android

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

Related

Android big image downloading prob : Out of memory

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

Load multiple Url images without using third party libraries in Recyclerview

Hi all I'm new to Android, I'm facing difficulty in loading Multiple images through URL into a Recycler view, My task is not to use any third Party Libraries and also not to add in string array in xml file. Is it Possible to loop an URL? for example "http://onethousandpaintings.com/imgs/numbers/number_1.png", if the number is change the image correspondingly changes.try it yourself once! I'm thinking an way to increment that number in a "For Loop" but could not figure it out. Kindly provide me an solution for it.
#sample AsycTask Code, you can pass the url to this class by execute method.
public class ShowImage extends AsyncTask<String,Void,Bitmap>{
private WeakReference<ImageView> imageview;
public ShowImage(ImageView imv){
imageview=new WeakReference<ImageView>(imv);
}
/** Background process
* input:url
* output: Bitmap image
* It passed into onPostExecute method
**/
#Override
protected Bitmap doInBackground(String... urls) {
return getBitMapFromUrl(urls[0]);
}
/** This method called after the doINputBackground method
* input:Bitmap image
* output: image set into the image view
* Image view passed from RecyclerViewOperation to ShowImage class through constructor
**/
#Override
protected void onPostExecute(Bitmap result) {
if((imageview!=null)&&(result!=null)){
ImageView imgview=imageview.get();
if(imgview!=null){
imgview.setImageBitmap(result);
}
}
}
/** This method called by doInBackground method
* input:url
* output: Bitmap image
*
**/
private Bitmap getBitMapFromUrl( String imageuri){
HttpURLConnection connection=null;
try {
URL url=new URL(imageuri);
// Log.d("bucky","bitmap" + imageuri);
connection= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream is=connection.getInputStream();
Bitmap mybitmap=BitmapFactory.decodeStream(is);
return mybitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
finally {
if(connection!=null) {
connection.disconnect();
}
}
}
}
You can use AsynTask so it will load multiple Images from the Url, which provides the functionality to work in Background. So Your main thread does not gets affected and the Images downloads in the backgreound continously. I hope this answer your Question.

downloading multiple file with download manager using jsoup and asynctask, not happening

Here is my code:--
public class grabber extends Activity
{
int counter;
String folderPath;
String[] array;
DownloadManager dm;
private long enqueue;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.data);
Down t = new Down();
t.execute();
}
private class Down extends AsyncTask<String, Void, String>
{
protected String doInBackground(String... params)
{
Log.i("grabber", "in back");
String w =Environment.getExternalStorageDirectory().getAbsoluteFile()+"/Android/data/myfolder";
createdir(w);
String link = "http://mywebsitehere.com";
Document doc;
array = new String[200];
try {
doc = Jsoup.connect(link).get();
String title = doc.title();
folderPath = w+ File.separator+title;
createdir(folderPath);
Elements images = doc.select("img[src~=(?i)\\.(png|jpe?g|gif)]");
counter =0;
for (Element image : images)
{
String img = image.attr("src");
array[counter]=img;
counter++;
}
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result)
{
Toast.makeText(getApplicationContext(),
"done", Toast.LENGTH_SHORT).show();
for(int i=0;i<counter;i++)
{
dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Request request = new Request(
Uri.parse(array[i]));
request.setDescription("Android Data download using DownloadManager.");
request.setDestinationInExternalFilesDir(getApplicationContext(),folderPath,File.separator+"pic"+Integer.toString(i)+".jpg");
enqueue = dm.enqueue(request);
}
}
}
public void createdir(String Path)
{
File file = new File(Path);
if(!file.exists())
{
file.mkdirs();
}
}
}
What it should do:-
It should download the given links, which contains images, to the given path.
What it does:-
The app is running quite fine, my UI is not hanging. After a few second "done" Toast is shown, which means theasynctask is completed and we are at onPostExecute. But when I check the dir I am seeing that there is no folder inside Android/data/myfolder.
The main setback is that some times it works, i.e. the images are downloaded and sometimes not.
So I am guessing maybe its because of some http timeout or some error which I am not handling correctly because I am using createdir(folderPath); after Jsoup and maybe the error is happening there so no folder is getting created there.
Any Ideas!?? Thanks in Advance.
Edit:-
I am getting SocketTimeoutException during jsoup.connect(link).get();
You have to add the following permission to the manifest of your application, to write to the external storage.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I hope you did this?
Finally I did it with some trial and error.
We can use timeout option here to reduce the Sockettimeoutexception by changing
doc = Jsoup.connect(link).get();
to
doc = Jsoup.connect(link).timeout(10000).get();
And there is still one other error, thats to remove the Toast message in the onPostExecute as we cannot interact without handler from background task to UI.
That's it.

Android: Load image on launch from URL

I am a learner and have been working on a home visitor app to get image from a URL of the visitor. Using the following code, which I found online, I was able to load image by adding an intent before the screen and adding a button on the screen saying "See Visitor Image" but now I want that my image should load as soon as the app launches. What changes could I make to do that? Thanks for your help.
OnClickListener getImageBtnOnClick = new OnClickListener() {
public void onClick(View view) {
Context context = view.getContext();
Editable ed = inputUrl.getText();
Drawable image = ImageOperations(context,ed.toString(),"image.jpg");
ImageView imgView = new ImageView(context);
imgView = (ImageView)findViewById(R.id.image1);
imgView.setImageDrawable(image);
}
};
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
inputUrl = ((EditText)findViewById(R.id.imageUrl));
inputUrl.setSingleLine();
inputUrl.setTextSize(11);
Button getImageButton = (Button)findViewById(R.id.getImageButton);
getImageButton.setOnClickListener(getImageBtnOnClick);
}
private Drawable ImageOperations(Context ctx, String url, String saveFilename) {
try {
InputStream is = (InputStream) this.fetch(url);
Drawable d = Drawable.createFromStream(is, "src");
return d;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public Object fetch(String address) throws MalformedURLException,IOException {
URL url = new URL(address);
Object content = url.getContent();
return content;
}
You can make use of SmartImageView, it is a drop-in replacement for Android’s standard ImageView which additionally allows images to be loaded from URLs or the user’s contact address book. Images are cached to memory and to disk for super fast loading.
https://github.com/loopj/android-smart-image-view
Or on OnResume of ur activity start downloading the image form the url as u r doing now in the click listener of button in a separate thread to avoid blocking main UI thread. Once you completed the download you can update the image view using handler from the worker thread.
You can make use of async task also instead of creating your own thread and handler to update UI. for more infor about async task refer following link http://www.vogella.com/articles/AndroidPerformance/article.html

Intermittent HttpClient GET issue on android

I have an android application i have been working on that downloads an image from a server, reads it into a bitmap and displays it on an ImageView
This works great most of the time, but every so often, it goes through the process (There is a ProgressDialog saying "Fetching image...") and once its done nothing gets displayed. There has not been anything in logcat that even seems to remotely relate to this.
Here is the code:
Bitmap image = null;
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(webService + "?cmd=get");
try
{
HttpResponse resp = client.execute(get);
Log.i("PhotoRouletteDebug", "Resp buffer size: " + (int)resp.getEntity().getContentLength());
InputStream is = resp.getEntity().getContent();
BufferedInputStream buf = new BufferedInputStream(is, (int)resp.getEntity().getContentLength());
image = BitmapFactory.decodeStream(buf);
// clean up
buf.close();
is.close();
Even when nothing is getting displayed, the Resp content length always reports a correct size but still, nothing ends up getting displayed.
This code is called from an AsyncTask, but only 1 task is ever called at a time.
This is driving me insane, i have no idea why its keeps doing this.
Edit: Here is the code that sets the imageView
// AsyncTask for Getting a new image from the queue
protected class GetImageTask extends AsyncTask<String, String, Bitmap>
{
protected void onPreExecute()
{
// lets show a progress dialog so the user knows something is going on
progressDialog = ProgressDialog.show(PhotoRoulette.this, "", "Fetching image...", true);
}
protected void onPostExecute (Bitmap image)
{
// we got a new photo so lets display it where it needs to be displayed
try
{
photoView = (ImageView)findViewById(R.id.photoView);
photoView.setImageBitmap(image);
}
catch (Exception e)
{
Log.e("Debug", "Something absolutely retarded happened", e);
}
// hide the progress dialog - we're all done
progressDialog.dismiss();
}
protected Bitmap doInBackground(String... urls)
{
// Get a new Bitmap Queue Image
Bitmap image = imageHandler.getQueueImage();
return image;
}
}
You didn't show us the code for displaying the image, so we don't know for sure that that code is correct. Perhaps the problem lies there?
But assuming that the problem is that the image is getting corrupted, here's how I'd start debugging this: Wrap buf with a PushbackInputStream. Read the bytes out of buf and save them to a file; then push those same bytes back into the PushbackInputStream. Then pass the PushbackInputStream into BitmapFactory.decodeStream. If the image is displayed successfully, then delete the file (manually or programatically.) Otherwise, you can now examine the bitmap at your leisure.

Categories

Resources