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.
Related
My internet connection is very fast. Despite that my image loads very slow in the app. Here is the code i have been using. As suggested I have been using async method to perform certain task seperately..
public class ItemPage extends Activity{
ImageView image;
String url;
#Override
protected void onCreate(Bundle savedInstanceState) {
image = (ImageView) findViewById(R.id.img);
//getting url from the parent activity
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if(extras != null) url = extras.getString("bigurl");
//async call
new DownloadFilesTask().execute();
}
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> { //working part
Drawable drawable;
#Override
protected Void doInBackground(Void... params) {
try {
drawable =drawableFromUrl(url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result) {
image.setImageDrawable(drawable);
}
}
public static Drawable drawableFromUrl(String url) throws IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return new BitmapDrawable(x);
}
}
Please help me. Is there any way to load the image faster from the url? Thanks in advance for your time.
i think you want to use Aquery Library .
it is load images very speedly.
refer this link
This works for me.
Bitmap mIcon_val;
URL newurl;
private void loadImage() {
Thread backgroundThread = new Thread() {
#Override
public void run() {
// do second step
try {
newurl = new URL(image_url);
mIcon_val = BitmapFactory.decodeStream(newurl
.openConnection().getInputStream());
} catch (MalformedURLException e) {
} catch (IOException e) {
}
Message msg = Message.obtain();
msg.what = 123;
handler.sendMessage(msg);
}
};
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 123:
imageView.setImageBitmap(mIcon_val);
break;
}
}
};
For calling the thread, you can use
backgroundThread.start();
My internet connection is very fast. Despite that my image loads very slow in the app.
It doesnt mean you can download image very fast when you have a really fast connection, it could be that the web server have a limit download speed for each connection, or the server is far from your current location. I would recommend to check the download speed of the server you are trying to connection first, if it is slow then it is not code but the server itself.
you may try using picasso library.it has several functions to compress,crop images that may help in downloading images at better rates.the link provides the full documentation of usage of the library-
http://square.github.io/picasso/
Here's something you can do to speed up the image processing side of things.
When you decode the stream you are converting it to an in-memory raster format. A 32bit image at 500x500 will take 1 mb of memory (500x500x4bytes). the native pixel format varies by device, and the fastest performance is to match the bitmap's pixel format to the system's pixel format so the system doesn't need to convert the image from it's native format to the window format.
Older devices in particular will use the 16 bit format. The image would be stored at 32bits, and then converted to 16bits when it's drawn to the screen. On these devices, you would be saving half the memory storage and avoiding a costly pixelwise conversion by decoding the image at 16 bits instead of at 32 bits. On newer devices that have the memory, it's better to store the image at 32 bits to avoid the conversion penalty.
So somewhere early on, store the pixel format that is used by the system. It will either be a 16 bit format (RGB_565) or a 32 bit format (8bits per pixel per color)
// default to 32 bits per pixel
Config bitmapConfig = Bitmap.Config.ARGB_8888 ; //RGB_565 | ARGB_8888
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
int bmp_cfg = wm.getDefaultDisplay().getPixelFormat();
if (bmp_cfg == PixelFormat.RGBA_8888 || bmp_cfg == PixelFormat.RGBX_8888 || bmp_cfg == PixelFormat.RGB_888){
bitmapConfig = Bitmap.Config.ARGB_8888;
} else {
bitmapConfig = Bitmap.Config.RGB_565;
}
Later, when you are decoding the bitmap, use the window manager's default pixel format so that it will create the bitmap with the correct pixel format while decoding (rather than converting in a second pass)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = bitmapConfig; // match pixel format to widnow system's format
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
bitmap = Bitmap.createBitmap(bitmap);
You can also play with the sample size to adjust the bitmap, but at 500x500 you probably need the whole image anyway.
there is a image gallery app which download images online. I want to know what will happen if phone memory/SD card get full; If an error will appear then what should I do?
This catches an OutofMemory error, but should check for other exceptions, too
URL aURL = null;
Bitmap bm = null;
try {
final String imageUrl = CMSServer + url;
aURL = new URL(imageUrl);
URLConnection conn = aURL.openConnection();
InputStream is = new BufferedInputStream(conn.getInputStream());
is = new BufferedInputStream(conn.getInputStream());
bm = BitmapFactory.decodeStream(is, null, options);
is.close();
} catch (OutOfMemory oom) {
// do something
}
}
return bm;
}
The analogy can be made what if a class cannot adjust more students ?
So according to me :-
1. you can follow "Precaution is better than cure"
first of all you will check the sdcard itself and if its say >1MB then you will get the image.
Even if the error comes you can prompt user to delete older images to allow new images like we used to have older phones where msg memory was limited and it will ask to remove older messages to allow new messages.
Still if you get the error then perhaps i cannot exactly figure out what to do except showing the "Out of memory exception" to user.
Thanks and hope it helps.... :)
It will through IOException if no memory is left in sdcard. But if you know the size of file which you are downloading then you can check for sufficient memory and thus can avoid IOException.
Edit: Catch Exception
try
{
//your code here
}
catch(IOException ex)
{
//do stuff when exception caused.
}
if you don't know how to use/catch exception. Please google it.
background
suppose i have an inputStream that was originated from the internet of a certain image file.
i wish to get information about the image file and only then to decode it.
it's useful for multiple purposes, such as downsampling and also previewing of information before the image is shown.
the problem
i've tried to mark&reset the inputStream by wrapping the inputStream with a BufferedInputStream , but it didn't work:
inputStream=new BufferedInputStream(inputStream);
inputStream.mark(Integer.MAX_VALUE);
final BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeStream(inputStream,null,options);
//this works fine. i get the options filled just right.
inputStream.reset();
final Bitmap bitmap=BitmapFactory.decodeStream(inputStream,null,options);
//this returns null
for getting the inputStream out of a url, i use:
public static InputStream getInputStreamFromInternet(final String urlString)
{
try
{
final URL url=new URL(urlString);
final HttpURLConnection urlConnection=(HttpURLConnection)url.openConnection();
final InputStream in=urlConnection.getInputStream();
return in;
}
catch(final Exception e)
{
e.printStackTrace();
}
return null;
}
the question
how can i make the code handle the marking an resetting ?
it works perfectly with resources (in fact i didn't even have to create a new BufferedInputStream for this to work) but not with inputStream from the internet...
EDIT:
it seems my code is just fine, sort of...
on some websites (like this one and this one), it fails to decode the image file even after reseting.
if you decode the bitmap (and use inSampleSize) , it can decode it fine (just takes a long time).
now the question is why it happens, and how can i fix it.
I believe the problem is that the call to mark() with the large value is overwritten by a call to mark(1024). As described in the documentation:
Prior to KITKAT, if is.markSupported() returns true, is.mark(1024) would be called. As of KITKAT, this is no longer the case.
This may be resulting in a reset() fail if reads larger than this value are being done.
(Here is a solution for the same problem, but when reading from disk. I didn't realize at first your question was specifically from a network stream.)
The problem with mark & reset in general here is that BitmapFactory.decodeStream() sometimes resets your marks. Thus resetting in order to do the actual read is broken.
But there is a second problem with BufferedInputStream: it can cause the entire image to be buffered in memory along side of where ever you are actually reading it into. Depending on your use case, this can really kill your performance. (Lots of allocation means lots of GC)
There is a really great solution here:
https://stackoverflow.com/a/18665678/1366
I modified it slightly for this particular use case to solve the mark & reset problem:
public class MarkableFileInputStream extends FilterInputStream
{
private static final String TAG = MarkableFileInputStream.class.getSimpleName();
private FileChannel m_fileChannel;
private long m_mark = -1;
public MarkableFileInputStream( FileInputStream fis )
{
super( fis );
m_fileChannel = fis.getChannel();
}
#Override
public boolean markSupported()
{
return true;
}
#Override
public synchronized void mark( int readlimit )
{
try
{
m_mark = m_fileChannel.position();
}
catch( IOException ex )
{
Log.d( TAG, "Mark failed" );
m_mark = -1;
}
}
#Override
public synchronized void reset() throws IOException
{
// Reset to beginning if mark has not been called or was reset
// This is a little bit of custom functionality to solve problems
// specific to Android's Bitmap decoding, and is slightly non-standard behavior
if( m_mark == -1 )
{
m_fileChannel.position( 0 );
}
else
{
m_fileChannel.position( m_mark );
m_mark = -1;
}
}
}
This won't allocate any extra memory during reads, and can be reset even if the marks have been cleared.
whether you can mark / reset a stream depends on the implementation of the stream. those are optional operations and aren't typically supported. your options are to read the stream into a buffer and then read from that stream 2x, or just make the network connection 2x.
the easiest thing is probably to write into a ByteArrayOutputStream,
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int count;
byte[] b = new byte[...];
while ((count = input.read(b) != -1) [
baos.write(b, 0, count);
}
now either use the result of baos.toByteArray() directly, or create a ByteArrayInputStream and use that repeatedly, calling reset() after consuming it each time.
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
that might sound silly, but there's no magic. you either buffer the data in memory, or you read it 2x from the source. if the stream did support mark / reset, it'd have to do the same thing in it's implementation.
Here is a simple method that always works for me :)
private Bitmap downloadBitmap(String url) {
// initilize the default HTTP client object
final DefaultHttpClient client = new DefaultHttpClient();
//forming a HttoGet request
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
//check 200 OK for success
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
// getting contents from the stream
inputStream = entity.getContent();
// decoding stream data back into image Bitmap that android understands
image = BitmapFactory.decodeStream(inputStream);
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
getRequest.abort();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + e.toString());
}
return image;
}
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
What is the simplest way to fetch an image from a url in an android program?
I would strongly recommend using an AsyncTask instead. I originally used URL.openStream, but it has issues.
class DownloadThread extends AsyncTask<URL,Integer,List<Bitmap>>{
protected List<Bitmap> doInBackground(URL... urls){
InputStream rawIn=null;
BufferedInputStream bufIn=null;
HttpURLConnection conn=null;
try{
List<Bitmap> out=new ArrayList<Bitmap>();
for(int i=0;i<urls.length;i++){
URL url=urls[i];
url = new URL("http://mysite/myimage.png");
conn=(HttpURLConnection) url.openConnection()
if(!String.valueOf(conn.getResponseCode()).startsWith('2'))
throw new IOException("Incorrect response code "+conn.getResponseCode()+" Message: " +getResponseMessage());
rawIn=conn.getInputStream();
bufIn=new BufferedInputStream();
Bitmap b=BitmapFactory.decodeStream(in);
out.add(b);
publishProgress(i);//Remove this line if you don't want to use AsyncTask
}
return out;
}catch(IOException e){
Log.w("networking","Downloading image failed");//Log is an Android specific class
return null;
}
finally{
try {
if(rawIn!=null)rawIn.close();
if(bufIn!=null)bufIn.close();
if(conn!=null)conn.disconnect();
}catch (IOException e) {
Log.w("networking","Closing stream failed");
}
}
}
}
Closing the stream/connection and exception handling is difficult in this case. According to Sun Documentation you should only need to close the outermost stream, however it appears to be more complicated. However, I am closing the inner most stream first to ensure it is closed if we can't close the BufferedInputStream.
We close in a finally so that an exception doesn't prevent them being closed. We account for the possibility of the streams will being null if an exception prevented them from being initialised. If we have an exception during closing, we simply log and ignore this. Even this might not work properly if a runtime error occurs .
You can use the AsyncTask class as follows. Start an animation in onPreExecute. Update the progress in onProgressUpdate. onPostExecute should handle the actual images. Use onCancel to allow the user to cancel the operation. Start it with AsyncTask.execute.
It is worth noting that the source code and the license allow us to use the class in non-Android projects.
You do it many ways but the simplist way I can think of would be something like this:
Bitmap IMG;
Thread t = new Thread(){
public void run(){
try {
/* Open a new URL and get the InputStream to load data from it. */
URL aURL = new URL("YOUR URL");
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. */
IMG = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
// ...send message to handler to populate view.
mHandler.sendEmptyMessage(0);
} catch (Exception e) {
Log.e(DEB, "Remtoe Image Exception", e);
mHandler.sendEmptyMessage(1);
} finally {
}
}
};
t.start();
And then add a handler to your code:
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch(msg.what){
case 0:
(YOUR IMAGE VIEW).setImageBitmap(IMG);
break;
case 1:
onFail();
break;
}
}
};
By starting a thread and adding a handler you are able to load the images without locking up the UI during download.