Jason,

Yeah, this is a good way to do it, and about as memory efficient as
you can get, and seems be more efficient than using a StringBuffer to
hold the response data, which another strategy I've seen for
downloading a response of unknown size. The issue there is that
eventually the underlying data structure for the StringBuffer gets
resized, and for any reasonably sized response, this happens multiple
times.

I'm fairly certain the difference in results when decoding from the SD
card vs from the network happens for two reasons. First, when
downloading an HTTP response, the HttpInputStream doesn't return how
large the response will be, whereas when reading from a file you
should be able to get the filesize. The second problem I suspect
arises because HttpInputStream.available() always returns 0. These two
issues mean that if downloading from the network is delayed you can
call read() on in HttpInputStream and get no bytes back and then call
available and it looks like there are no more bytes available. I
believe this may be what is throwing off BitmapFactory.decodeStream().

Cheers,
Justin
Android Team @ Google

On Aug 3, 6:06 pm, Jason <[email protected]> wrote:
> Pulkit,
>
> I had a similar problem. It seems that BitmapFactory silently fails
> (returning null) when BufferedInputStream blocks while fetching from
> the connection (I think). If the BufferedInputStream is coming from an
> SD source, it works because it doesn't block (I think). The solution
> for me was to download the entire stream as a byte array first, and
> then call BitmapFactory.decodeByteArray(...)
>
> To do that efficiently, I got the advice to read bytes from a
> DataInputStream, filling up fixed sized chunks at a time until the
> input stream is finished, and then copying the data from those chunks
> into a final byte array (now that we know the full size of the
> download). Here's some example code for this:
>
> ///////////////////////////////////////////////////////////////
> // example of using Bitmapfactory.decodeByteArray instead of
> Bitmapfactory.decodeStream
>
>     public static Bitmap fetchImage(URL url, String userAgent) throws
> IOException {
>         byte[] bitmapByteArray = JsonUtils.fetchUrlBytes(url,
> userAgent );
>         Bitmap bm = BitmapFactory.decodeByteArray(bitmapByteArray, 0,
> bitmapByteArray.length);
>         return bm;
>     }
>
> ///////////////////////////////////////////////////////////////
> // example of downloading a byte array in chunks
>
>     private static final int CHUNKSIZE = 8192;        //size of fixed
> chunks
>     private static final int BUFFERSIZE = 1024;       //size of
> reading buffer
>
>     public static byte[] fetchUrlBytes(URL url, String userAgent )
> throws IOException {
>
>         HttpURLConnection connection = null;
>
>         connection = ( HttpURLConnection ) url.openConnection();
>         if(userAgent != null) {
>             connection.setRequestProperty("User-Agent", userAgent);
>         }
>         connection.setConnectTimeout(5000);
>         connection.setReadTimeout(5000);
>
>         int bytesRead = 0;
>         byte[] buffer = new byte[BUFFERSIZE];   //initialize buffer
>         byte[] fixedChunk = new byte[CHUNKSIZE]; //initialize 1st
> chunk
>         ArrayList<byte[]> BufferChunkList = new ArrayList<byte[]>(); //
> List of chunk data
>         int spaceLeft = CHUNKSIZE;
>         int chunkIndex = 0;
>
>         DataInputStream in = new DataInputStream
> ( connection.getInputStream() );
>
>         while( ( bytesRead = in.read( buffer ) ) != -1 ) { //loop
> until the DataInputStream is completed
>             if(bytesRead > spaceLeft) {
>                 //copy to end of current chunk
>                 System.arraycopy(buffer, 0, fixedChunk, chunkIndex,
> spaceLeft);
>                 BufferChunkList.add(fixedChunk);
>
>                 //create a new chunk, and fill in the leftover
>                 fixedChunk = new byte[CHUNKSIZE];
>                 chunkIndex = bytesRead - spaceLeft;
>                 System.arraycopy(buffer, spaceLeft, fixedChunk, 0,
> chunkIndex);
>             } else {
>                 //plenty of space, just copy it in
>                 System.arraycopy(buffer, 0, fixedChunk, chunkIndex,
> bytesRead);
>                 chunkIndex = chunkIndex + bytesRead;
>             }
>             spaceLeft = CHUNKSIZE - chunkIndex;
>         }
>
>         if (in != null) {
>             in.close();
>         }
>
>         // copy it all into one big array
>         int responseSize = (BufferChunkList.size() * CHUNKSIZE) +
> chunkIndex;
>
>         byte[] responseBody = new byte[responseSize];
>         int index = 0;
>         for(byte[] b : BufferChunkList) {
>             System.arraycopy(b, 0, responseBody, index, CHUNKSIZE);
>             index = index + CHUNKSIZE;
>         }
>
>         System.arraycopy(fixedChunk, 0, responseBody, index,
> chunkIndex);
>
>         return responseBody;
>     }
>
> On Jul 28, 10:55 pm, Pulkit <[email protected]> wrote:
>
>
>
> > Hi All,
>
> > In my app I am downloading images from a remote server and putting it
> > into a gallery and displaying it. The problem is that when i do it on
> > the emulator it works absolutely fine but when i do it on the phone
> > few of the images come and a few arenull. I tried many ways but I am
> > not able to find the perfect way. The images on my server are of 50 kb
> > max. But still some are downloaded and rest are not. it would be
> > really great if someone could help me asap coz i need to make this app
> > live by this weekend.
>
> > Here is the code snippet to download the images from the server.
>
> > public Bitmap getImage(String photoUrl) {
> >                 Bitmap image =null;
> >                 if (!photoUrl.equals("")) {
> >                         if(photoUrl.contains(" ")) {
> >                                 photoUrl = photoUrl.replaceAll(" ", "%20");
> >                         }
> >                                 try {
> >                                         URLConnection conn = new 
> > URL(photoUrl).openConnection();
> >                                         conn.connect();
> >                                         InputStream inStream = 
> > conn.getInputStream();
> >                                         BufferedInputStream bis = new 
> > BufferedInputStream(inStream);
>
> >                                         image 
> > =BitmapFactory.decodeStream(bis);
>
> >                                         bis.close();
> >                                         inStream.close();
> >                                 } catch (MalformedURLException e) {
> >                                         e.printStackTrace();
> >                                 } catch (IOException e) {
> >                                         image 
> > =BitmapFactory.decodeResource(getResources(),
> > R.drawable.image_not_available);
> >                                 }
> >                 } else {
> >                         image =BitmapFactory.decodeResource(getResources(),
> > R.drawable.image_not_available);
> >                 }
> >                 return image;
> >         }
>
> > Also is there any other way of loading the images in a seperate thread
> > like it happens in the android market.
> > please reply.
>
> > Thanks
> > Pulkit
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to