I've been working on this issue for several days and I can't figure out what I'm doing wrong. I'm making an inventory/store app for a project where the user can input what items they have in stock into a list. As per the requirements I need to give it picture taking capability and I need to be able to save the picture in the SQLite database. That part I have achieved. But when I attempt to update an item and save it again to the list, the image returns null. I've attached pictures to visually explain...
Main activity
New item page
Save an item to the Main Activity listview
Click on an item to edit
Unless I take a new picture, when i save the updated item, the icon image returns null
I'm using a CursorLoader. I've treated the image the same way I treated all the other columns in the database... so I can't figure out why it won't stick.
Here's the code pertaining to images in EditorActivity:
Bitmap photos;
// Content URI for the existing item (null if it's a new item)
private Uri mCurrentItemUri;
// Picture taking capability with button
public void takePicture(View view) {
PackageManager pm = this.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
} else {
Toast.makeText(EditorActivity.this, "Sorry! You don't have a camera app.", Toast.LENGTH_SHORT).show();
}
}
// Once image is taken, save to image view and then save to db as a ByteArray
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
photos = (Bitmap) extras.get("data");
mImageView.setImageBitmap(photos);
}
}
// Get user input from editor and save item into database.
private void saveItem() {
// Read from input fields
// Use trim to eliminate leading or trailing white space
String nameString = mNameEditText.getText().toString().trim();
String priceString = mPriceEditText.getText().toString().trim();
// Find quantity TV by id and extract int value as String
TextView quantityTextView = (TextView) findViewById(R.id.quantity_editor_text_view);
String quantityString = quantityTextView.getText().toString();
ImageView iconImage = (ImageView) findViewById(R.id.image_view_editor);
// Check if this is supposed to be a new item and check if all the fields in the editor are blank
if (mCurrentItemUri == null && TextUtils.isEmpty(nameString)
&& TextUtils.isEmpty(priceString) && TextUtils.isEmpty(quantityString) && iconImage == null) {
// Since no fields were modified, we can return early without creating a new item.
// No need to create ContentValues and no need to do any ContentProvider operations.
return;
}
// Create a ContentValues object where column names are the keys and item attributes from the editor are the values.
ContentValues values = new ContentValues();
// Find image by the member variable "photos" and get the bytes
byte[] bytes = Utils.getImageBytes(photos);
values.put(ItemEntry.IMAGE_VIEW, bytes);
values.put(ItemEntry.COLUMN_NAME, nameString);
int price = 0;
if (!TextUtils.isEmpty(priceString)) {
price = Integer.parseInt(priceString);
}
values.put(ItemEntry.COLUMN_PRICE, price);
values.put(ItemEntry.COLUMN_QUANTITY, quantityString);
// Determine if this is a new or existing item by checking if mCurrentItemUri is null or not
if (mCurrentItemUri == null) {
// This is a NEW item, so insert a new item into the provider,
// returning the content URI for the new item.
Uri newUri = getContentResolver().insert(ItemEntry.CONTENT_URI, values);
// Show a toast message depending on whether or not the insertion was successful.
if (newUri == null) {
// If the new content URI is null, then there was an error with insertion.
Toast.makeText(this, getString(R.string.insert_item_failed), Toast.LENGTH_SHORT).show();
} else {
// Otherwise, the insertion was successful and we can display a toast.
Toast.makeText(this, getString(R.string.insert_item_successful), Toast.LENGTH_SHORT).show();
}
} else {
// Otherwise this is an EXISTING item, so update the item with content URI: mCurrentItemUri
// and pass in the new ContentValues. Pass in null for the selection and selection args
// because mCurrentItemUri will already identify the correct row in the database that
// we want to modify.
int rowsAffected = getContentResolver().update(mCurrentItemUri, values, null, null);
// Show a toast message depending on whether or not the update was successful.
if (rowsAffected == 0) {
// If no rows were affected, then there was an error with the update.
Toast.makeText(this, getString(R.string.edit_item_failed), Toast.LENGTH_SHORT).show();
} else {
// Otherwise, the update was successful and we can display a toast.
Toast.makeText(this, getString(R.string.edit_item_successful), Toast.LENGTH_SHORT).show();
}
}
}
And the Utils file for the image methods:
public class Utils {
// Used in saveItem
// Adding the if/else statement here allows the picture to be null
// But now the picture disappears when you update an item without taking a new pic.
public static byte[] getImageBytes(Bitmap bitmap) {
if (bitmap != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
return stream.toByteArray();
} else {
return null;
}
}
// Used in OnLoadFinished (Editor) and cursor adapter
public static Bitmap getImage(byte[] image) {
return BitmapFactory.decodeByteArray(image, 0, image.length);
}
}
I'm fairly certain the issue lies in the saveItem method but let me know if you'd like to see the whole file.