开发者

Problem creating a Drawable from a SQLite Blob

开发者 https://www.devze.com 2023-01-12 05:36 出处:网络
I\'m caching image f开发者_JAVA技巧iles as a blob in a SQLite database.I have a similar application on another platform that does the same thing with the same image files.The databases on both platfor

I'm caching image f开发者_JAVA技巧iles as a blob in a SQLite database. I have a similar application on another platform that does the same thing with the same image files. The databases on both platforms report the exact same size for the same images. So I think, but can't guarantee, that the image data is getting into the database intact.

But when I try to create a Drawable, the console prints out "DEBUG/skia(267): --- decoder->decode returned false".

The steps are:

  1. Read the blob into a byte array.

    byte[] b = new byte[imageDataCursor.getInt(0)];

    b = imageDataCursor.getBlob(1);

  2. Create an InputStream from the byte array.

    ByteArrayInputStream is = new ByteArrayInputStream(b);

  3. Create a Drawable from the InputStream. (this is what creates the 'decoder' message above)

    Drawable drw = Drawable.createFromStream(is, "articleImage");

  4. Set the ImageView.image to the Drawable.

    imgView.setImageDrawable(drw);

So far, no joy. Any suggestions?


I'll post my solution to help anyone with a similar problem.

I tried testing the byte array I'm reading from the database by writing it to a file and then viewing the file. It turns out that the blob data in the database is not complete - I get a few lines of the image, but not the entire image.

The solution involved creating a BufferedInputStream and a ByteArrayBuffer to read in the image from the remote server. The code to capture an image file from a remote server and create a byte array to be able to write it to a sqlite database looks like this:

             try {
             HttpGet getMethod=new HttpGet(url);
                HttpClient client=new DefaultHttpClient();
             HttpResponse response = client.execute(getMethod);
             HttpEntity entity = response.getEntity();
             InputStream in = entity.getContent();
             BufferedInputStream bis = new BufferedInputStream(in);
             ByteArrayBuffer baf = new ByteArrayBuffer(50);
             int current = 0;
             while ((current = bis.read()) != -1) {
              baf.append((byte) current);
             }
             byte[] b = baf.toByteArray();
           database.updateArticleWithImageData(b, imageKey);
         }
         catch (Throwable t) {
          android.util.Log.e("MyApp", "Exception fetching image file", t);
         }


I chased my tail around on this for quite a while. The answer from deSelby helped me. Here is my code that downloads images (PNG and JPG) from Facebook, then stores / retrieves the data from a sqlite table using the path as a reference.

As you can see, it actually attempts to read the image from the table first, if it is there it simply returns it, otherwise it fetches it from Facebook, stores it in the database and then returns it.

private static Drawable fetchPhoto(ContentResolver cr, int source, String path) {
    Drawable image = null;
    myDB mDb = myDB.getInstance();
    Cursor iCursor = mDb.fetchImage(cr, path);
    if(iCursor != null && iCursor.moveToFirst()) {              
        byte[] bb = iCursor.getBlob(iCursor.getColumnIndex(Images.IMAGE));
        if(iCursor != null) iCursor.close();
        image = new BitmapDrawable(BitmapFactory.decodeByteArray(bb, 0, bb.length));
    } else {
        if(iCursor != null) iCursor.close();
        //get image from path
        try
        {
            InputStream is = (InputStream) new URL(path).getContent();
            BufferedInputStream bis = new BufferedInputStream(is);
             ByteArrayBuffer baf = new ByteArrayBuffer(50);
             int current = 0;
             while ((current = bis.read()) != -1) {
              baf.append((byte) current);
             }
             byte[] barray = baf.toByteArray();
            bis.close();
            is.close();
            /* write image to db */
            long id = mDb.writeImage(cr,source,path,barray);
            image =  new BitmapDrawable(BitmapFactory.decodeByteArray(barray, 0, barray.length));               
        }catch (Exception error) {
            //System.out.println("Exc="+e);
        }
    }
    return image;
}

My writeImage looks like this (see below).

Images.IMAGE references the name of a BLOB column in my table. The main point here is really that you can write the byte[] directly to the database BLOB column. I write the time (utc) so I can clear old data in accordance with the Facebook api policies on caching data.

public long writeImage(ContentResolver contentResolver, int source, String path, byte[] image) {

    Time now = new Time();
    now.setToNow();
    ContentValues initialValues = new ContentValues();      
    initialValues.put(Images.IMAGE, image);
    initialValues.put(Images.SOURCE, source);
    initialValues.put(Images.PATH, path); 
    initialValues.put(Images.UTC, now.toMillis(false));
    if(source == 0) initialValues.put(Images.DIRTY, 1); // sync user created images

    Uri newUri = contentResolver.insert(Images.CONTENT_URI, initialValues);
    String Id = newUri.getPathSegments().get(1);
    return Long.parseLong(Id);

}

I use a content provider for my db, but for those who don't the insert code looks like this, which you can use directly into your database without a provider. (FYI only).

rowId = db.insert(IMAGES_TABLE, null, values);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号