SQLite image blob to string - android

I'm trying to get a blob from sqlite to string, please see below:
ArrayList<Sudentdb> list;
GridView gridView;
final String[] from = new String[] { SQLiteHelper._ID,
SQLiteHelper.NAME, SQLiteHelper.AGE, SQLiteHelper.PROFILE };
final int[] to = new int[] { R.id.rowid, R.id.txtName, R.id.studentage, R.id.profileimageV };
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.studentfragment, null);
gridView = (GridView) v.findViewById(R.id.gridView);
DBManager dbManager = new DBManager(getActivity());
dbManager.open();
Cursor cursor = dbManager.fetch();
list = new ArrayList<>();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(), R.layout.single_item, cursor, from, to, 0);
gridView.setAdapter(adapter);
I have tested returning only the text and it returns correctly, but with images I get a error:
android.database.sqlite.SQLiteException: unknown error (code 0): Unable to convert BLOB to string
I assume that I first have to get the image from the database?? Any help?
EDIT
I understand why you would think that this question is a duplicate of SimpleCursorAdapter how to show an image? but in that question the image is stored in the drawable folder and he is saving and calling the name of that image as a string into sqlite. In my case, the image is in the gallery and I save it as a blob into SQLite (In another activity) and now I am trying to get the blob back from the database and displaying it in a GridView.
So in the answer the following will not work for me:
int resID = getApplicationContext().getResources().getIdentifier(cursor.getString(columnIndex), "drawable", getApplicationContext().getPackageName());
IV.setImageDrawable(getApplicationContext().getResources().getDrawable(resID));

You can use this to get blob as byte[] from SQLITE
byte[] img = cursor.getBlob(cursor.getColumnIndex(IMG_SRC));
then convert byte[] to bitmap using below Util method ...
public static Bitmap getbitmap(byte[] img) {
return BitmapFactory.decodeByteArray(img, 0, img.length);
}

Related

Handle Blob data type through ContentValues

I am trying to store and retrieve image data in Sqlite Db.
To do so I firstly stored in local device memory an example pic (path: storage/emulated/0/Download/).
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private final String SAMPLE_IMAGE_PATH = "/storage/emulated/0/Download/image.jpg";
Then I set up an insert method to feed the db with these example data:
private void insertProduct() {
// Create a ContentValues object where column names are the keys,
// and sample attributes are the values.
ContentValues values = new ContentValues();
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_NAME, sampleName);
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_QTY, sampleQty);
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_PRICE, SamplePrice);
values.put(InventoryContract.ProductEntry.COLUMN_EMAIL, sampleMail);
values.put(InventoryContract.ProductEntry.COLUMN_PHONE, samplePhone);
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_PIC, SAMPLE_IMAGE_PATH);
//insert a new row
Uri newUri = getContentResolver().insert(InventoryContract.ProductEntry.CONTENT_URI,values);
}
and I define the onCreateLoader method as follows:
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Define a projection that specifies the columns from the table we care about.
String[] projection = {
InventoryContract.ProductEntry._ID,
InventoryContract.ProductEntry.COLUMN_PRODUCT_PIC,
InventoryContract.ProductEntry.COLUMN_PRODUCT_PRICE,
InventoryContract.ProductEntry.COLUMN_PRODUCT_QTY,
InventoryContract.ProductEntry.COLUMN_PRODUCT_NAME};
// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this,
InventoryContract.ProductEntry.CONTENT_URI,
projection,
null,
null,
null);
}
In the CursorAdapter class I updated the listView adding the data from db in bindView() method:
public void bindView(View view, Context context, Cursor cursor) {
// Find individual views that we want to modify in the list item layout
TextView nameTextView = (TextView) view.findViewById(R.id.prod_name);
TextView priceTextView = (TextView) view.findViewById(R.id.prod_price);
TextView qtyTextView = (TextView) view.findViewById(R.id.prod_qty);
ImageView prodImageView = (ImageView) view.findViewById(R.id.prod_img);
// Find the columns of attributes that we're interested in
int nameColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_NAME);
int priceColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_PRICE);
int qtyColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_QTY);
int picColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_PIC);
// Read the attributes from the Cursor for the current product
String prodName = cursor.getString(nameColumnIndex);
Double prodPrice = cursor.getDouble(priceColumnIndex);
int prodQty = cursor.getInt(qtyColumnIndex);
byte [] prodImg = cursor.getBlob(picColumnIndex);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[1024 * 32];
Bitmap bmp = BitmapFactory.decodeByteArray(prodImg, 0, prodImg.length, options);
//Update Views
nameTextView.setText(String.valueOf(prodName));
priceTextView.setText(prodPrice.toString());
qtyTextView.setText(String.valueOf(prodQty));
prodImageView.setImageBitmap(bmp);
}
}
When I try execute this code everything goes ok, but I see a blank image instead of both the selected pic and placer pic.
So I think that there is some problem with inserting data into db.
I am trying to store and retrieve image data in Sqlite Db
I do not recommend this. Store the images in files. Store data in the rows that identifies the files.
Then I set up an insert method to feed the db with these example data
You are storing a string in COLUMN_PRODUCT_PIC. You are not storing a byte[]. This is good, relative to my recommendation. This is bad relative to your data-retrieval code, where you are attempting to retrieve a byte[].

Path/URI from sqlite load into Listview

I have a listview that loads information from sqlite database. The information should load image this way:
This is the code for the listview activity:
private void populateListViewFromDB() {
Cursor cursor = myDb.getAllRows();
// Allow activity to manage lifetime of the cursor.
// DEPRECATED! Runs on the UI thread, OK for small/short queries.
startManagingCursor(cursor);
// Setup mapping from cursor to view fields:
String[] fromFieldNames = new String[]
{DBAdapter.KEY_DATE, DBAdapter.KEY_IMG, DBAdapter.KEY_FAVCOLOUR};
int[] toViewIDs = new int[]
{R.id.item_date, R.id.item_icon, R.id.item_kcal};
// Create adapter to may columns of the DB onto elemesnt in the UI.
SimpleCursorAdapter myCursorAdapter =
new SimpleCursorAdapter(
this, // Context
R.layout.item_layout, // Row layout template
cursor, // cursor (set of DB records to map)
fromFieldNames, // DB Column names
toViewIDs // View IDs to put information in
);
// Set the adapter for the list view
ListView myList = (ListView) findViewById(R.id.listViewFromDB);
myList.setAdapter(myCursorAdapter);
}
Theoretically, I'm trying to save the string "snapPath" to the field "KEY_IMG" and load the image into imageview "item_icon". If the user does not snap a photo, by default, the imageview will load a drawable instead.
At the Add activity page, I added a string and save that string to the database:
String snapPath = "res/drawable-xxhdpi/ic_launcher.png"; //by default it will load a drawable
myDb.insertRow(date, snapPath, kcal+" kcal"); //saves into database
Also in Add activity page, the code for capturing and saving the image into my phone:
private void doTakePicture() {
// create a File object for the parent directory
File newDir = new File( Environment.getExternalStorageDirectory(), "/myFoodDiary/snaps");
newDir.mkdirs();
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
//for file name
Date cDate = new Date();
final String fDate = new SimpleDateFormat("yyyyMMMd").format(cDate);
final String fTime = new SimpleDateFormat("HHmmss").format(cDate);
String snapName = "mFD-" + fDate + fTime + ".jpg";
fileJpeg = new File(newDir, snapName);
snapPath = "/myFoodDiary/snaps/"+String.valueOf(snapName);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(fileJpeg));
startActivityForResult(takePictureIntent, TAKE_PIC_REQ);
}
Thanks in advance!
To customize whether to draw a bitmap from storage or a drawable from your resources, you can't use SimpleCursorAdapter anymore. You need to derive a new class from CursorAdapter and use that.
Conditionally loading the images is not as trivial as it seems. I recommend using the Android Query library image loading methods which support placeholders, fallbacks, and asynchronous loading - just what you need.

Android GridView with database

I've got problem with my grid view. I would like to store images in table and then display them in grid view.
// ImageAdapter
String[] strings = db.getPictures();
Integer[] ints = new Integer[strings.length];
for (int i=0; i < strings.length; i++) {
ints[i] = Integer.parseInt(strings[i]);
}
imageView.setImageResource(ints[position]);
return imageView;
//DatabaseHandler
public String[] getPictures(){
int i=0;
String selectQuery = "SELECT pictureName FROM Category";
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.rawQuery(selectQuery, null);
int rowsNumber=c.getCount();
String[] mThumbIds;
mThumbIds= new String[rowsNumber];
if (c.moveToFirst()) {
do {
mThumbIds[i]=c.getString(0);
i++;
} while (c.moveToNext());
}
return mThumbIds;
}
And when i run my app it crush at starting. Single string I save like R.drawable.ic_work
In most scenarios, your device wont be able to load a single original image into memory leave alone a list. You need to scale your image before you display it.
As you said you are saving R.drawable.ic_work as string.
The problem is you are using imageView.setImageResource(ints[position]); while R.drawable.ic_work is String.
Solution is instead of storing R.drawable.ic_work as String store it as int because your R.drawable.ic_work represents with an int ID.

SQLite BLOB column to SimpleCursorAdapter with ViewBinder

I'm trying to display a list of contacts that are currently stored in a SQLiteDatabase.
Previously I've retrieved ContactsContract.Contacts.PHOTO_THUMBNAIL_URI and stored it in a form of byte[] in the BLOB column of my database rows.
Now when I'm trying to extract the thumbnails back, by decoding them to Bitmaps in MyBinderView class, the pictures don't appear, instead I see empty spaces(the default image, ic_launcher, is showed correctly). My ListView row layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="1dp">
<ImageView
android:id="#+id/thumbnail"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="50dp"
android:layout_marginRight="1dp"
android:src="#drawable/ic_launcher"/>
<TextView
android:id="#+id/email"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_width="0dp"
android:layout_weight="5"
android:layout_height="wrap_content"/>
</LinearLayout>
ListFragment class:
//DataBaseHelper.PHOTO contains a BLOB fetched from sqlite database
//DataBaseHelper.NAME is a String (no problem here)
String[] from = { DataBaseHelper.PHOTO, DataBaseHelper.NAME };
int[] to = new int[] { R.id.thumbnail, R.id.email };
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
setEmptyText("No E-mail buddies found");
// We have a menu item to show in action bar.
// setHasOptionsMenu(true);
contacts = new DataBaseHelper(getActivity());
contacts.open();
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(), R.layout.contacts,
null, from, to);
mAdapter.setViewBinder(new MyViewBinder());
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
ViewBinder class for the photo to be inserted correctly:
public class MyViewBinder implements ViewBinder{
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.thumbnail:
ImageView picture = (ImageView) view;
byte[] blob = cursor.getBlob(columnIndex);
if(blob!=null){
picture.setImageBitmap(
BitmapFactory.decodeByteArray(blob, 0, blob.length)
);
}
else
picture.setImageResource(R.drawable.ic_launcher);
return true;
}
return false;
}
}
Any help would be appreciated.
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI
Provides a path to the thumbnail that can be retrieved by.
So after understanding that you build a URI using this path by calling parse function.
next you query your new uri with the help of this embedded class -
private static class PhotoQuery {
public static final String[] PROJECTION = {
Photo.PHOTO
};
public static final int PHOTO = 0;
}
using the code bellow you'll extract the needed byte[] that solved the issue.
the point of getting byte[] is to be able to store it in your DB and manipulate it later on when needed.
private byte[] getImage(String uriString){
if(uriString==null)
return null;
Uri myuri = Uri.parse(uriString);
Cursor photoCursor = getContentResolver().query(myuri, PhotoQuery.PROJECTION, null, null, null);
if (photoCursor != null) {
try {
if (photoCursor.moveToFirst()) {
final byte[] photoBytes = photoCursor.getBlob(PhotoQuery.PHOTO);
if (photoBytes != null) {
return photoBytes;
}
}
} finally {
photoCursor.close();
}
}
return null;
}
Hope it'll help someone
cheers :)

Dynamically show images from resource/drawable

I'm trying to put different images (.jpg , .png) dynamically into a ListView from res/drawable .
The names from the images I get from a database.
The images themselves are in the res/drawable folder.
This is what I already have, With an error of :D
String imgName; --> There are the img names I need from the database
Drawable drawable;
drawable = Class.appContext.getResources().getDrawable(Class.appContext.getResources().getIdentifier("com.example.test:drawable/"+imgName,null,null));
Then I get this into a ArrayList for every image in the database(+- 200 images):
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> map = new HashMap<String, Object>();
map = new HashMap<String, Object>();
map.put("img",drawable);
map.put("text", "some text");
list.add(map);
Now I RETURN list;
In the Class where I call :
listReceive = Class.getImages(appContext);
listSetup = new SimpleAdapter(this, listReceive, R.layout.row,
new String[] {"img", "text"}, new int[] {R.id.IMG_CELL, R.id.TEXT_CELL});
lvList.setAdapter(listSetup);
XML row is an ImageView and a TextView.
System.out :resolveUri failed on bad
bitmap uri:
android.drawable.bitmapDrawable#405739
resolveUri failed on bad bitmap uri:
android.drawable.bitmapDrawable#405639
resolveUri failed on bad bitmap uri:
android.drawable.bitmapDrawable#405959
resolveUri failed on bad bitmap uri:
android.drawable.bitmapDrawable#405677...
... ...
I got it working when I saved images into local or SDcard memory, and then put the path inside the arraylist like:
map.put("img","/data/data/com.example.test/images/" + imgName);
I can't use this because then i will need to copy the pictures from res/drawable onto local or SD.This takes up 2 times the memory. can't have that of.
There must be a way to get images dynamically from the drawable.
Any one knows what I'm missing here?
Thanks.
The SimpleAdapter expects an integer or string that specifies a resource or image URI:
public void setViewImage (ImageView v, String value)
Since: API Level 1
Called by bindView() to set the image for an ImageView but only if there is no existing ViewBinder or if the existing ViewBinder cannot handle binding to an ImageView. By default, the value will be treated as an image resource. If the value cannot be used as an image resource, the value is used as an image Uri. This method is called instead of setViewImage(ImageView, int) if the supplied data is not an int or Integer.
I believe should use setViewBinder to provide a ViewBinder for the SimpleAdapter to handle binding the Drawable data to the ImageView. Basically, the setViewValue() method should return false unless it is called for your image view. When it is called for your image view, the method should set the data in the view and return true. The return value indicates whether the ViewBinder was able to set the view or whether the adapter should try to bind the data itself via its default behavior.
Maybe something like:
private final SimpleAdapter.ViewBinder mViewBinder =
new SimpleAdapter.ViewBinder() {
#Override
public boolean setViewValue(
final View view,
final Object data,
final String textRepresentation) {
if (view instanceof ImageView) {
((ImageView) view).setImageDrawable((Drawable) data);
return true;
}
return false;
}
};
...
listSetup .setViewBinder(mViewBinder);
I've done a similar thing with a SimpleCursorAdapter and its ViewBinder.
The simple adapter expects String in the map. But your map contains a drawable for the key "img".
Instead try extending the BaseAdapter class. Override the getView method and then manually set the drawable to the imageview and text to textview.
Another thought, it might not be a good idea to keep every drawable in memory. Rather get the drawable dynamically while rendering that particular row of the list
This following method or way also works - if anyone is still interested
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
Integer flags[] = new Integer[listdetail.size()];
Resources resources = getResources();
for (int i = 0; i < listdetail.size(); i += 2) {
listName = listdetail.get(i).getName();
int dynamicId = resources.getIdentifier(listdetail.get(i).getName().replaceAll(" ", "").toLowerCase(), "drawable", getActivity().getPackageName());
if(dynamicId == 0) {
dynamicId = R.drawable.test_image;
flags[i] = dynamicId;
}else {
flags[i] = dynamicId;
}
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("value1", listdetail.get(i).getName());
hm.put("valueImage1", Integer.toString(flags[i]));
list.add(hm);
}
String[] from = { "value1", "valueImage1"};
int[] to = { R.id.textview, R.id.imageView };
SimpleAdapter adapter = new SimpleAdapter(getActivity().getBaseContext(), list, R.layout.listlayout, from, to);
ListView listView = (ListView) getActivity().findViewById(R.id.listview);
listView.setAdapter(adapter);

Categories

Resources