使用ViewBinder、SimpleCursorAdapter、SQLite,在ListView上显示相机拍摄的图片
Using ViewBinder, SimpleCursorAdapter, SQLite, to show pictures taken by a camera on ListView
这个程序应该做的是当它启动时,当点击 activity 栏上的相机图标时,将打开一个相机,如果用户拍照并确定保存它会将图片保存在数据库中,并且在相机实例消失后,照片将立即作为 ListView 中的缩略图显示在主页上。
然而到目前为止,我一直收到一个 SQLiteException 说 "unknown error (code 0): INTEGER data in nativeGetBlob"。
每次在我 运行 我的代码进行一些调试之后,我都会完全删除我的数据库,这样它就会有一个新的开始。在我的数据库中,实际上存储过程显然没问题,因为我使用 adb 检查我的数据库,我的命令提示符显示 table 有两列,第一列是 _id,第二列是图像列,图片以 .PNG 格式存储。作为 byte[],并且 ID 是自动递增的。
我已经成功地将一张测试图像显示为一个简单的 ImageView(具有相同的 SQLite 存储代码),但是当我尝试在 ListView 上显示它时,使用 ViewBinder 和 SimpleCursorAdapter 我得到了 SQLiteException。我在这里阅读了许多其他问题,并尝试了一整天的解决方案,但仍然卡住了。有知道如何调试我的程序的专家吗?
到目前为止,这是我的代码:
MainActivity.java:
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import java.io.ByteArrayOutputStream;
public class MainActivity extends ActionBarActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = this.openOrCreateDatabase("images.db", Context.MODE_PRIVATE, null);
db.execSQL("create table if not exists tb ( _id INTEGER PRIMARY KEY AUTOINCREMENT, image blob)");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
//dispatchTakePictureIntent();
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
//Calling dispatchTakePictureIntent to start the camera activity
dispatchTakePictureIntent();
return true;
}
return super.onOptionsItemSelected(item);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
/*Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ImageView thumb1 = (ImageView) findViewById(R.id.thumb1);
thumb1.setImageBitmap(imageBitmap);*/
////////////////////////////////////////////////////////////////////////
Bundle extras = data.getExtras();
Bitmap imageTaken = (Bitmap) extras.get("data");
ContentValues values = new ContentValues();
//calculate how many bytes our image consists of.
/* int bytes = imageTaken.getByteCount();
//or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
//int bytes = b.getWidth()*b.getHeight()*4;
ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
imageTaken.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
byte[] toValuesPut = buffer.array(); //Get the underlying array containing the data.
*/
byte[] toValuesPut = this.getBytes(imageTaken);
values.put("image", toValuesPut);
db.insert("tb", null, values);
getImage();
///////////////////////////////////////////////////////////////
db.close();
}
}
protected void getImage(){
Cursor c = db.rawQuery("select * from tb", null);
if (c.moveToNext()){
//byte[] image = c.getBlob(0);
//Bitmap bmp = BitmapFactory.decodeByteArray(image, 0, image.length);
//ImageView thumb1 = (ImageView) findViewById(R.id.thumb1);
// thumb1.setImageBitmap(bmp);
ListView listView = (ListView) findViewById(R.id.sampleListView);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.photos, c, new String[] { "_id", "image" }, new int[]{R.id.col1, R.id.col2});
SimpleCursorAdapter.ViewBinder viewBinder = new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor,
int columnIndex) {
ImageView image = (ImageView) view;
byte[] byteArr = cursor.getBlob(columnIndex);
image.setImageBitmap(BitmapFactory.decodeByteArray(byteArr, 0, byteArr.length));
return true;
}
};
ImageView image = (ImageView) findViewById(R.id.editimage);
viewBinder.setViewValue(image, c, c.getColumnIndex("_id"));
adapter.setViewBinder(viewBinder);
listView.setAdapter(adapter);
}
}
public static byte[] getBytes(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
return stream.toByteArray();
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:weightSum="1">
<TableRow
android:id="@+id/tableRow1"
android:layout_width="793dp"
android:layout_height="wrap_content"
android:layout_weight="0.23" >
<TextView android:id="@+id/col1"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:width="50dp"
android:textSize="18sp"
/>
<TextView android:id="@+id/col2"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:width="150dp"
android:textSize="18sp"
/>
<ImageView android:id="@+id/editimage"
android:clickable="true"
android:onClick="ClickHandlerForEditImage"
android:layout_width="35dp"
android:layout_height="35dp"/>
</TableRow>
</LinearLayout>
menu_main.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:icon="@drawable/camera"
android:orderInCategory="100"
app:showAsAction="ifRoom" />
</menu>
listview.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ListView
android:id="@+id/sampleListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:divider="#CCCCCC"
android:dividerHeight="1dp"
android:paddingLeft="2dp" >
</ListView>
</LinearLayout>
photos.xml:
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/thumb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="24sp"/>
Logcat:
Caused by: android.database.sqlite.SQLiteException: unknown error (code 0): INTEGER data in nativeGetBlob
at android.database.CursorWindow.nativeGetBlob(Native Method)
at android.database.CursorWindow.getBlob(CursorWindow.java:403)
at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:45)
at hiew1.is2.byuh.edu.mydailyselfie.MainActivity.setViewValue(MainActivity.java:133)
at hiew1.is2.byuh.edu.mydailyselfie.MainActivity.getImage(MainActivity.java:139)
at hiew1.is2.byuh.edu.mydailyselfie.MainActivity.onActivityResult(MainActivity.java:108)
at android.app.Activity.dispatchActivityResult(Activity.java:6192)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3573)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3620)
at android.app.ActivityThread.access00(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
非常感谢
也许您可以尝试按照此示例进行操作,而不使用 ViewBinder 和 SimpleCursorAdapter。只需使用 bindblob() 方法和 Cursor:
How to store image in SQLite database
这个程序应该做的是当它启动时,当点击 activity 栏上的相机图标时,将打开一个相机,如果用户拍照并确定保存它会将图片保存在数据库中,并且在相机实例消失后,照片将立即作为 ListView 中的缩略图显示在主页上。
然而到目前为止,我一直收到一个 SQLiteException 说 "unknown error (code 0): INTEGER data in nativeGetBlob"。
每次在我 运行 我的代码进行一些调试之后,我都会完全删除我的数据库,这样它就会有一个新的开始。在我的数据库中,实际上存储过程显然没问题,因为我使用 adb 检查我的数据库,我的命令提示符显示 table 有两列,第一列是 _id,第二列是图像列,图片以 .PNG 格式存储。作为 byte[],并且 ID 是自动递增的。
我已经成功地将一张测试图像显示为一个简单的 ImageView(具有相同的 SQLite 存储代码),但是当我尝试在 ListView 上显示它时,使用 ViewBinder 和 SimpleCursorAdapter 我得到了 SQLiteException。我在这里阅读了许多其他问题,并尝试了一整天的解决方案,但仍然卡住了。有知道如何调试我的程序的专家吗?
到目前为止,这是我的代码:
MainActivity.java:
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import java.io.ByteArrayOutputStream;
public class MainActivity extends ActionBarActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = this.openOrCreateDatabase("images.db", Context.MODE_PRIVATE, null);
db.execSQL("create table if not exists tb ( _id INTEGER PRIMARY KEY AUTOINCREMENT, image blob)");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
//dispatchTakePictureIntent();
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
//Calling dispatchTakePictureIntent to start the camera activity
dispatchTakePictureIntent();
return true;
}
return super.onOptionsItemSelected(item);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
/*Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ImageView thumb1 = (ImageView) findViewById(R.id.thumb1);
thumb1.setImageBitmap(imageBitmap);*/
////////////////////////////////////////////////////////////////////////
Bundle extras = data.getExtras();
Bitmap imageTaken = (Bitmap) extras.get("data");
ContentValues values = new ContentValues();
//calculate how many bytes our image consists of.
/* int bytes = imageTaken.getByteCount();
//or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
//int bytes = b.getWidth()*b.getHeight()*4;
ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
imageTaken.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
byte[] toValuesPut = buffer.array(); //Get the underlying array containing the data.
*/
byte[] toValuesPut = this.getBytes(imageTaken);
values.put("image", toValuesPut);
db.insert("tb", null, values);
getImage();
///////////////////////////////////////////////////////////////
db.close();
}
}
protected void getImage(){
Cursor c = db.rawQuery("select * from tb", null);
if (c.moveToNext()){
//byte[] image = c.getBlob(0);
//Bitmap bmp = BitmapFactory.decodeByteArray(image, 0, image.length);
//ImageView thumb1 = (ImageView) findViewById(R.id.thumb1);
// thumb1.setImageBitmap(bmp);
ListView listView = (ListView) findViewById(R.id.sampleListView);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.photos, c, new String[] { "_id", "image" }, new int[]{R.id.col1, R.id.col2});
SimpleCursorAdapter.ViewBinder viewBinder = new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor,
int columnIndex) {
ImageView image = (ImageView) view;
byte[] byteArr = cursor.getBlob(columnIndex);
image.setImageBitmap(BitmapFactory.decodeByteArray(byteArr, 0, byteArr.length));
return true;
}
};
ImageView image = (ImageView) findViewById(R.id.editimage);
viewBinder.setViewValue(image, c, c.getColumnIndex("_id"));
adapter.setViewBinder(viewBinder);
listView.setAdapter(adapter);
}
}
public static byte[] getBytes(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
return stream.toByteArray();
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:weightSum="1">
<TableRow
android:id="@+id/tableRow1"
android:layout_width="793dp"
android:layout_height="wrap_content"
android:layout_weight="0.23" >
<TextView android:id="@+id/col1"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:width="50dp"
android:textSize="18sp"
/>
<TextView android:id="@+id/col2"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:width="150dp"
android:textSize="18sp"
/>
<ImageView android:id="@+id/editimage"
android:clickable="true"
android:onClick="ClickHandlerForEditImage"
android:layout_width="35dp"
android:layout_height="35dp"/>
</TableRow>
</LinearLayout>
menu_main.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:icon="@drawable/camera"
android:orderInCategory="100"
app:showAsAction="ifRoom" />
</menu>
listview.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ListView
android:id="@+id/sampleListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:divider="#CCCCCC"
android:dividerHeight="1dp"
android:paddingLeft="2dp" >
</ListView>
</LinearLayout>
photos.xml:
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/thumb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="24sp"/>
Logcat:
Caused by: android.database.sqlite.SQLiteException: unknown error (code 0): INTEGER data in nativeGetBlob
at android.database.CursorWindow.nativeGetBlob(Native Method)
at android.database.CursorWindow.getBlob(CursorWindow.java:403)
at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:45)
at hiew1.is2.byuh.edu.mydailyselfie.MainActivity.setViewValue(MainActivity.java:133)
at hiew1.is2.byuh.edu.mydailyselfie.MainActivity.getImage(MainActivity.java:139)
at hiew1.is2.byuh.edu.mydailyselfie.MainActivity.onActivityResult(MainActivity.java:108)
at android.app.Activity.dispatchActivityResult(Activity.java:6192)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3573)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3620)
at android.app.ActivityThread.access00(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
非常感谢
也许您可以尝试按照此示例进行操作,而不使用 ViewBinder 和 SimpleCursorAdapter。只需使用 bindblob() 方法和 Cursor:
How to store image in SQLite database