如何从android中的数据库中检索大型BLOB? [英] How to retrieve a large BLOB from database in android?

查看:74
本文介绍了如何从android中的数据库中检索大型BLOB?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我像这样将图像字节保存到数据库。

  byte [] imagebyte = getBytes(bitmap); 
boolean isuploaded = myDb.insertData(all_receipts,imagebyte);




public byte [] getBytes(Bitmap bitmap){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG,70,stream);

return stream.toByteArray();
}

然后我在我的数据库助手类中创建了一个检索方法来检索所有数据。

  public ArrayList< Model.Receipts> convertoArray(String tablename){
ArrayList< Model.Receipts> receiptsArrayList = new ArrayList<>();
Model.Receipts收据;

SQLiteDatabase database = this.getReadableDatabase();
String selectQuery =SELECT * FROM all_receipts;


if(tablename.equalsIgnoreCase(all_receipts)){

Cursor cursor = database.rawQuery(selectQuery,null);

if(cursor.moveToFirst()){
do {
int indexnumber = cursor.getInt(0);
Bitmap image = getImage(cursor.getBlob(1));
receipt = new Model.Receipts(image,indexnumber);

receiptsArrayList.add(收据);
}
while(cursor.moveToNext());
}
}
return receiptsArrayList;

}

这与我从中捕获的图像的缩略图一样正常相机。但是当我对完整尺寸的图像使用相同的方法时,它不起作用。我收到错误


 无法启动活动

java.lang .IllegalStateException:无法从
读取第0行,第0列

CursorWindow。在访问数据之前,请确保正确初始化Cursor。 at



android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2255)at> android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2309)at?> android .app.ActivityThread.access $在> android.app.ActivityThread $ H.handleMessage 700(ActivityThread.java:157)(ActivityThread.java:1289)




 据我所知,这是因为BLOB在数据库中太大了。 

那么如何从数据库中调用所有图像?

解决方案

您应该将图像的路径存储到数据库中,并使用路径访问/显示图像。






示例



以下是一个示例,为方便起见,图像(image001.JPG到image010.JPG)存储在assets文件夹中。



该示例显示图像的列表(ListView),以及1图像并单击列表中的项目会更改显示以通过存储的路径显示相应的图像。



首先布局 activity_main.xml 注意包名称必须相应更改): -

 <?xml version = 1.0encoding =utf-8?> 
< LinearLayout xmlns:android =http://schemas.android.com/apk/res/android
xmlns:tools =http://schemas.android.com/tools
机器人:取向= 垂直
机器人:layout_width = match_parent
机器人:layout_height = match_parent
工具:上下文= mjt.sqliteexamples.MainActivity >
< ListView
android:id =@ + id / imagelist
android:layout_width =match_parent
android:layout_height =wrap_content>
< / ListView>
< ScrollView
android:layout_width =match_parent
android:layout_height =match_parent>
< LinearLayout
android:orientation =vertical
android:layout_width =match_parent
android:layout_height =match_parent>
< ImageView
android:id =@ + id / myimage
android:layout_width =wrap_content
android:layout_height =wrap_content
android: contentDescription = MYIMAGE/>
< / LinearLayout>
< / ScrollView>
< / LinearLayout>

DatabaseHelper ImgDBHelper.java

 公共类ImgDBHelper扩展SQLiteOpenHelper {

public static final String DBNAME =myimagestore;
public static final String TBLNAME =images;
public static final String ID_COL =_ id;
public static final String DSCR_COL =description;
public static final String PATH_COL =path; //<<<<<<<<

SQLiteDatabase db;

ImgDBHelper(上下文上下文){
super(context,DBNAME,null,1);
db = this.getWritableDatabase();
}
@覆盖
公共无效的onCreate(SQLiteDatabase分贝){
字符串crtsql = CREATE TABLE IF NOT EXISTS + TBLNAME + ( +
ID_COL + INTEGER PRIMARY KEY,+
DSCR_COL +TEXT,+
PATH_COL +TEXT+
);
db.execSQL(crtsql);
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase,int i,int i1){

}

public void addImageRow(String path,String description){
Cursor csr = db.query(TBLNAME,null,PATH_COL +=?,new String [] {path},null,null,null);

//不要添加重复图像(根​​据路径)
if(csr.getCount()> 0){
csr.close();
返回;
}
csr.close();

ContentValues cv = new ContentValues();
cv.put(DSCR_COL,description);
cv.put(PATH_COL,path);

db.insert(TBLNAME,null,cv);
}

public Cursor getAllImages(){
return db.query(TBLNAME,null,null,null,null,null,null);
}

public String getImagePathFromID(long id){
String rv =;
Cursor csr = db.query(TBLNAME,
null,
_id =?,
new String [] {Long.toString(id)},
null,null,null
);
if(csr.moveToFirst()){
rv = csr.getString(csr.getColumnIndex(PATH_COL));
}
csr.close();
返回rv;
}

public boolean areImagesLoaded(){
Cursor csr = db.query(TBLNAME,null,null,null,null,null,null);
boolean rv =(csr.getCount()> 0);
csr.close();
返回rv;
}
}

活动 MainActivity.java

 公共类MainActivity扩展AppCompatActivity {

Drawable d; //可绘制图像
String imagepath =image001.JPG; //初始图片
ImgDBHelper imgdbhlpr; // DB Helper
ListView imagelist; // ListView
SimpleCursorAdapter sca; // ListView的游标适配器
光标图像; // ListView的光标
ImageView iv; // ImageView显示图像

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imagelist =(ListView)findViewById(R.id.imagelist);
iv =(ImageView)findViewById(R.id.myimage);

imgdbhlpr = new ImgDBHelper(this);

//如果没有图像加载表格
if(!imgdbhlpr.areImagesLoaded()){
for(int i = 1; i< 11; i ++) {

String path =image+
String.format(%03d,i)+
.JPG
;
imgdbhlpr.addImageRow(path,Image+
String.format(%03d,i));
}
}

//获取包含所有行的游标
images = imgdbhlpr.getAllImages();

//准备listview的适配器
sca = new SimpleCursorAdapter(这个,
android.R.layout.simple_list_item_1,
图片,
新字符串[ ] {ImgDBHelper.DSCR_COL},
new int [] {android.R.id.text1},
0
);

//设置ListView的onItemClick侦听器,以便在点击
//项目将显示在相应的图像
imagelist.setOnItemClickListener(新AdapterView.OnItemClickListener(){
@覆盖
public void onItemClick(AdapterView<?> adapterView,View view,int i,long l){
iv.setImageDrawable(d = getImageFromAssets(
imgdbhlpr.getImagePathFromID(l)
));
}
});
imagelist.setAdapter(sca);

//设置初始图像(image001.JPG)
d = getImageFromAssets(imagepath);
iv.setImageDrawable(d);
}


//根据提供的路径创建drawable的例程
private Drawable getImageFromAssets(String imagepath){
Drawable drawable = null;
AssetManager am = this.getAssets();
InputStream = null;
try {
is = am.open(imagepath);
} catch(例外e){
e.printStackTrace();
}
try {
drawable = Drawable.createFromStream(is,null);
}最后{
try {
is.close();
= null;
} catch(例外e){
e.printStackTrace();
}
}
返回drawable;
}
}

最初运行时: -





然后点击Listview(image004): -




I save an image byte to database like this.

 byte[] imagebyte = getBytes(bitmap);
 boolean isuploaded = myDb.insertData("all_receipts",imagebyte);




 public byte[] getBytes(Bitmap bitmap) {
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 70, stream);

    return stream.toByteArray();
}

And then I have a retrieve method I created in my database helper class to retrieve all the data.

   public ArrayList<Model.Receipts> convertoArray(String tablename){
    ArrayList<Model.Receipts> receiptsArrayList = new ArrayList<>();
    Model.Receipts receipt;

    SQLiteDatabase database = this.getReadableDatabase();
    String selectQuery = "SELECT * FROM all_receipts";


    if(tablename.equalsIgnoreCase("all_receipts")){

        Cursor cursor = database.rawQuery(selectQuery, null);

        if (cursor.moveToFirst()) {
            do {
                int indexnumber = cursor.getInt(0);
                Bitmap image = getImage(cursor.getBlob(1));
                receipt = new Model.Receipts(image,indexnumber);

                receiptsArrayList.add(receipt);
            }
            while (cursor.moveToNext());
        }
    }
    return receiptsArrayList;

}

This was working fine with thumbnail of the image i captured from camera. But when I use the same method for a full sized image, it does not work. I get the error

Unable to start activity 

   java.lang.IllegalStateException: Couldn't read row 0, col 0 from 

CursorWindow. Make sure the Cursor is initialized correctly before accessing data >from it. at

android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2255) at >android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2309) at ?>android.app.ActivityThread.access$700(ActivityThread.java:157) at >android.app.ActivityThread$H.handleMessage(ActivityThread.java:1289)

From which I know that it's because that the BLOB is too big in the database. 

So how can I call all the images from the database ?

解决方案

You should store the path of the image into the database and the use the path to access/display the image.


An Example

The following is an example where, for convenience, the images (image001.JPG through to image010.JPG) are stored in the assets folder.

The example displays a list (ListView) of the images, along with 1 image and clicking on an item in the list changes the display to show the respective image via the stored path.

First the layout activity_main.xml (note package name would have to be changed accordingly) :-

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="mjt.sqliteexamples.MainActivity">
    <ListView
        android:id="@+id/imagelist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <ImageView
                android:id="@+id/myimage"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:contentDescription="myImage"/>
        </LinearLayout>
    </ScrollView>
</LinearLayout>

The DatabaseHelper ImgDBHelper.java

public class ImgDBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "myimagestore";
    public static final String TBLNAME = "images";
    public static final String ID_COL = "_id";
    public static final String DSCR_COL = "description";
    public static final String PATH_COL = "path"; //<<<<<<<<

    SQLiteDatabase db;

    ImgDBHelper(Context context) {
        super(context,DBNAME,null,1);
        db = this.getWritableDatabase();
    }
    @Override
    public void onCreate(SQLiteDatabase db) {    
        String crtsql = "CREATE TABLE IF NOT EXISTS " + TBLNAME + "(" +
                ID_COL + " INTEGER PRIMARY KEY, " +
                DSCR_COL + " TEXT," +
                PATH_COL + " TEXT" +
                ")";
        db.execSQL(crtsql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }

    public void addImageRow(String path, String description) {
        Cursor csr = db.query(TBLNAME,null,PATH_COL + "=?",new String[]{path},null,null,null);

        // DO NOT ADD DUPLICATE IMAGES (according to path)
        if (csr.getCount() > 0) {
            csr.close();
            return;
        }
        csr.close();

        ContentValues cv = new ContentValues();
        cv.put(DSCR_COL,description);
        cv.put(PATH_COL,path);

        db.insert(TBLNAME,null,cv);
    }

    public Cursor getAllImages() {
        return db.query(TBLNAME,null,null,null,null,null,null);
    }

    public String getImagePathFromID(long id) {
        String rv = "";
        Cursor csr = db.query(TBLNAME,
                null,
                "_id=?",
                new String[]{Long.toString(id)},
                null,null,null
        );
        if (csr.moveToFirst()) {
            rv = csr.getString(csr.getColumnIndex(PATH_COL));
        }
        csr.close();
        return rv;
    }

    public boolean areImagesLoaded() {
        Cursor csr = db.query(TBLNAME,null,null,null,null,null,null);
        boolean rv = (csr.getCount() > 0);
        csr.close();
        return rv;
    }
}

And the Activity MainActivity.java

public class MainActivity extends AppCompatActivity {

    Drawable d;                        // drawable for the image
    String imagepath = "image001.JPG"; // initial image
    ImgDBHelper imgdbhlpr;             // DB Helper
    ListView imagelist;                // ListView
    SimpleCursorAdapter sca;           // ListView's Cursor adapter
    Cursor images;                     // Cursor for the ListView
    ImageView iv;                      // The ImageView to display the image

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imagelist = (ListView) findViewById(R.id.imagelist);
        iv = (ImageView) findViewById(R.id.myimage);

        imgdbhlpr = new ImgDBHelper(this);

        // Load the table if there are no images
        if (!imgdbhlpr.areImagesLoaded()) {
            for (int i=1;i < 11;i++) {

                String path = "image" +
                        String.format("%03d",i) +
                                ".JPG"
                        ;
                imgdbhlpr.addImageRow(path,"Image " +
                String.format("%03d",i));
            }
        }

        // get a cursor with all of the rows
        images = imgdbhlpr.getAllImages();

        // prepare the listview's adapter
        sca = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1,
                images,
                new String[]{ImgDBHelper.DSCR_COL},
                new int[]{android.R.id.text1},
                0
        );

        // set the Listview's onItemClick listener so that clicking an
        // item displays the respective image
        imagelist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                iv.setImageDrawable(d = getImageFromAssets(
                        imgdbhlpr.getImagePathFromID(l)
                ));
            }
        });
        imagelist.setAdapter(sca);

        // set the initial image (image001.JPG)
        d = getImageFromAssets(imagepath);
        iv.setImageDrawable(d);
    }


    // routine to create a drawable according to the supplied path
    private  Drawable getImageFromAssets(String imagepath) {
        Drawable drawable = null;
        AssetManager am = this.getAssets();
        InputStream is = null;
        try {
            is = am.open(imagepath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            drawable = Drawable.createFromStream(is,null);
        } finally {
            try {
                is.close();
                is = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return drawable;
    }
}

When initially run :-

And then after clicking on the Listview (image004) :-

这篇关于如何从android中的数据库中检索大型BLOB?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆