0

I asked a similar question a month ago but didn't really get an answer that helped, so I wanted to see if I could better phrase the question.

I am working with an app that stores BLOB data in a database. The data is a picture image, very small (less then 2KB). I decided to dave them directly into the database because of the size.

I am still learning about programming, and I'm sure I'm missing something simple, but here is my issue. I have a lot of text fields in my database, and I pull information from them using this method:

private void fillData() {

    // Pulls the fields from the database and assigns them to the columns

    String[] from = new String[] { BorrowMeTable.COLUMN_ITEM,
            BorrowMeTable.COLUMN_NAME, BorrowMeTable.COLUMN_DATE };

    // The label for each textview
    int[] to = new int[] { R.id.label, R.id.pName, R.id.pDate };

    getLoaderManager().initLoader(0, null, this);
    adapter = new SimpleCursorAdapter(this, R.layout.bm_row, null, from,
            to, 0);

    setListAdapter(adapter);
}

My class implements LoaderManager.LoaderCallbacks and the accompanying methods are as follows:

public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    // Remove to show all records - This sets up the list to filter based on
    // items returned
    String mSelection = BorrowMeTable.COLUMN_BORROW_FLAG + "=?";

    // SQL request for only returned items to be shown
    String[] selectionArgs = { "Borrowed" }; // The actual argument

    String[] projection = { BorrowMeTable.COLUMN_ID,
            BorrowMeTable.COLUMN_ITEM, BorrowMeTable.COLUMN_NAME,
            BorrowMeTable.COLUMN_DATE };
    // mSelection & selectionArgs can be removed and set to null to display
    // all records
    CursorLoader cursorLoader = new CursorLoader(this,
            BorrowMeContentProvider.CONTENT_URI, projection, mSelection,
            selectionArgs, null);
    return cursorLoader;
}

When I attempt to add the column that has the blob data in it - I get an error saying I cannot convert a blob to a string:

06-30 15:13:36.152: E/AndroidRuntime(842): android.database.sqlite.SQLiteException: unknown error (code 0): Unable to convert BLOB to string

I know this is because I'm attempting to read it as a string like everything else, but I'm at a loss for how to grab it properly using this method. I'm loading the data into rows of a listactivity.

Can anyone help point me in the right direction? I've not found a lot online dealing with cursor loader and listview.

Thanks

Update - I created a new bindview for the simple cursor adaptor but i still get the following error message:

07-02 20:42:53.350: E/AndroidRuntime(798): FATAL EXCEPTION: main
07-02 20:42:53.350: E/AndroidRuntime(798): android.database.sqlite.SQLiteException:           unknown error (code 0): Unable to convert BLOB to string
07-02 20:42:53.350: E/AndroidRuntime(798):  at  android.database.CursorWindow.nativeGetString(Native Method)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.database.CursorWindow.getString(CursorWindow.java:434)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.database.CursorWrapper.getString(CursorWrapper.java:114)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:150)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.CursorAdapter.getView(CursorAdapter.java:250)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.AbsListView.obtainView(AbsListView.java:2159)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.ListView.measureHeightOfChildren(ListView.java:1246)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.ListView.onMeasure(ListView.java:1158)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.View.measure(View.java:15518)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.RelativeLayout.measureChild(RelativeLayout.java:666)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:477)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.View.measure(View.java:15518)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4825)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.View.measure(View.java:15518)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.LinearLayout.measureVertical(LinearLayout.java:847)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.View.measure(View.java:15518)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4825)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
07-02 20:42:53.350: E/AndroidRuntime(798):  at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2176)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.View.measure(View.java:15518)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1874)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1089)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1265)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.Choreographer.doCallbacks(Choreographer.java:562)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.Choreographer.doFrame(Choreographer.java:532)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.os.Handler.handleCallback(Handler.java:725)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.os.Handler.dispatchMessage(Handler.java:92)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.os.Looper.loop(Looper.java:137)
07-02 20:42:53.350: E/AndroidRuntime(798):  at android.app.ActivityThread.main(ActivityThread.java:5041)
07-02 20:42:53.350: E/AndroidRuntime(798):  at java.lang.reflect.Method.invokeNative(Native Method)
07-02 20:42:53.350: E/AndroidRuntime(798):  at java.lang.reflect.Method.invoke(Method.java:511)
07-02 20:42:53.350: E/AndroidRuntime(798):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
07-02 20:42:53.350: E/AndroidRuntime(798):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
07-02 20:42:53.350: E/AndroidRuntime(798):  at dalvik.system.NativeStart.main(Native Method)

This is the code I have used for my view binder:

public class MyViewBinder implements ViewBinder {

@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
    // TODO Auto-generated method stub

    int viewId = view.getId();

    Log.i("ViewBinder: view", Integer.toString(viewId));
    Log.i("ViewBinder: name",cursor.getString(2));
    Log.i("ViewBinder: email",cursor.getString(3));
    Log.i("ViewBinder: photo",cursor.getBlob(4)==null?"NO Photo":"Has photo");

    switch(viewId){

    case R.id.pic_of_item:

        ImageView storedItem = (ImageView) view;

        byte[] blob = cursor.getBlob(columnIndex);

        // If the blob is null then pull it from database
        if (blob != null){

            // Decode the bitmap from the blob
            storedItem.setImageBitmap(BitmapFactory.decodeByteArray(blob, 0, blob.length));

            Log.i("RETURN TRUE BLOB",cursor.getString(3));

        } else {

            // If nothing is found use the camera icon from drawable 
            storedItem.setImageResource(R.drawable.take_camera_small);

            Log.i("RETURN TRUE NO BLOB",cursor.getString(3));

            return true;
        }

    }

    Log.i("RETURN FALSE",cursor.getString(3));

    return false;
}

}

Vince
  • 45
  • 12

1 Answers1

1

SimpleCursorAdapter uses cursor.getString to retrieve the value from the database, as seen in the source code. For images, it assume the String value it retrieved is the integer that points to a particular image resource (i.e., calls v.setImageResource(Integer.parseInt(value))). Hence, SimpleCursorAdapter has no understanding of how to deal with blob data and you'll need to use your own CursorAdapter class that does the proper conversion from blob to Bitmap to set onto your ImageView, probably using something like the following code in your bindView:

ImageView imageView = // get your ImageView
byte[] blob = cursor.getBlob(cursor.getColumnIndex(BorrowMeTable.COLUMN_ITEM));
Bitmap bitmap = BitmapFactory.decodeByteArray(blob, 0, blob.length);
imageView.setImageBitmap(bitmap);
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • I was able to create my own viewbinder using the steps from the article [here](http://stackoverflow.com/questions/9951871/sqlite-blob-column-to-simplecursoradapter-with-viewbinder) but I still get an error message about String to Blob – Vince Jul 03 '13 at 00:47
  • @Vince - so you've set up a `ViewBinder` that has a switch looking for `BorrowMeTable.COLUMN_ITEM`? `getString` is only called within `bindView` if your `ViewBinder` returns `false`. Have you confirmed (via `Log` statements or debugging) that your `ViewBinder` is handling the image and returning `true`? – ianhanniballake Jul 03 '13 at 01:02
  • I have confirmed via log statements that it returns tru and then false just after. I have posted my View Binder code above – Vince Jul 03 '13 at 01:30
  • Thanks again for any help you can provide - I'm stil new and trying to get the hang of this. – Vince Jul 03 '13 at 01:31
  • @Vince - it looks like you are only returning `true` when `blob==null` (your `else` statement) - move that `return true;` statement out of the `else` statement so that both paths return `true`. – ianhanniballake Jul 03 '13 at 02:34