【问题标题】:How to insert and retrieve image from Sqlite database in Android Studio如何在 Android Studio 中从 Sqlite 数据库中插入和检索图像
【发布时间】:2019-06-03 17:06:54
【问题描述】:

我正在尝试从用户那里获取一些数据,包括相机拍摄的照片,然后将其插入数据库(缩略图),然后检索它以供稍后查看。 1- I used this and this

但我仍然收到错误

此错误中提到的第 45 行在这里:

这是响应用户输入的 OnclickListener。

sginUpButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String Fname = fn.getText().toString();
            String Lname = ln.getText().toString();
            String Email = em.getText().toString();
            String Pass = pass.getText().toString();
            String mobile = mob.getText().toString();
            if(fn.length()!=0 && ln.length()!=0  && em.length()!=0 && pass.length()!=0&& mob.length()!=0)
            {
                AddData(Fname,Lname,Email,Pass,mobile,byteArray);
                fn.setText("");
                ln.setText("");
                em.setText("");
                pass.setText("");
                mob.setText("");
                Intent fromLoginToSignup = new Intent(SignUpScreen.this, Profile.class);
                notification();
            }
            else
            {
                toastmessage("lazem temla kol al fara3'at");
            }

        }
    });

最后,这是它在数据库中插入的部分,我认为在插入的图像方面存在实际错误。

 public void onCreate(SQLiteDatabase db) {
    String createTable="CREATE TABLE "+ TABLE_NAME + "(ID INTEGER PRIMARY KEY AUTOINCREMENT , "
            + FN + " TEXT , "
            + LN + " TEXT ,"
            + E_M + " TEXT ,"
            + PASS + " TEXT ,"
            + Mobnum + " INTEGER, "
            + image + " BLOB)";
    db.execSQL(createTable);

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
    onCreate(db);

}
public boolean addData(String FirstName,String LastName,String Email,String Password,String MobileNumber, byte[] Profileimg) //to write into the datbase
{
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues cv =new ContentValues();
    cv.put(FN,FirstName);
    cv.put(LN,LastName);
    cv.put(E_M,Email);
    cv.put(PASS,Password);
    cv.put(Mobnum,MobileNumber);
    cv.put(image, Profileimg);

    Log.d(DATABASE_NAME,"adding : " + FirstName + " TO " + TABLE_NAME );
    long result=db.insert(TABLE_NAME,null,cv);
    //if  the result inserted correctly or not
    if(result==-1)
    {
        return false;
    }
    else
    {
        return true;
    }
}

我在网上获得了这两个函数,所以我认为将它们放在这里很重要,但我认为它们与错误有关,但我不能确定

    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) {
        Bitmap photo = (Bitmap) data.getExtras().get("data");
        img.setImageBitmap(photo);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byteArray = stream.toByteArray();
    }
}

【问题讨论】:

  • 请不要发布代码、XML 或 logcat 输出的屏幕截图。请将所有文本作为文本发布。此外,将图像存储在数据库中通常不是一个好主意。将它们保存为存储中的文件,并将它们的路径存储在数据库中。
  • @MikeM。是的,我从其他来源收集了尽可能多的信息,但鉴于时间限制,我必须这样做。
  • 问题在于如何检索图像,因为您将图像放在字符串列表中,尝试检索并将其放置在列表视图中。将图像插入数据库。将位图转换为 byte[] 以从数据库中检索。将 byte[] 转换为位图。
  • 更好地将图像名称保存到数据库并将图像保存在存储中,只要确定路径就可以很容易地从数据库调用
  • @jhayjhay 关于我插入图片的部分,我将其转换为 byte[],你会在最后一张图片中找到它。关于检索图像,我不确定你的意思,但我试图将它放在列表视图中,并且在我发布的另外 2 个 SO 问题中,它成功了。

标签: android sqlite


【解决方案1】:

如果您不想使用 blob,这是一种替代解决方案。您可以实现如下,

  • 将图像位图转换为base64,并保存为sqlite中的文本。
  • 检索时,将该 base64 转换为位图并在 ImageView 中显示。

转换码请参考here

【讨论】:

    【解决方案2】:

    消息表明 bytes 为空。 getBlob 的文档说明:-

    该列的结果以及该方法是否抛出异常 值为 null 或列类型不是 blob 类型 实现定义。

    因此,我相信 getBlob 返回一个空值,因此很可能是空值被插入。

    根据您的 DatabaseHelper 考虑以下事项:-

        mDB = new DatabaseHelper(this);
        mDB.addData("Test001", "Test001", "email", "password", "xxc", null);
        mDB.addData("Test002", "Test002", "email", "password", "xxc", new byte[]{0});
        Cursor csr = mDB.getData();
        DatabaseUtils.dumpCursor(csr);
    
        while (csr.moveToNext()) {
            bytes = csr.getBlob(6);
            if (bytes == null) {
                Log.d("OUCH", "Row " + String.valueOf(csr.getPosition()) + " is null");
            } else {
                Log.d("OK", "Row " + String.valueOf(csr.getPosition()) + " has byte array of length " + bytes.length);
            }
            Log.d("REPLICATE"," byte array length is " + bytes.length);
        }
    

    这会添加两行,第一行以 null 作为 byte[](图像),第二行有一个有效的,尽管它是短 byte[]。

    插入行没有问题。

    数据提取没有问题。

    但是日志将包含以下内容:-

    2019-01-09 14:15:31.622 2783-2783/ptfc.populatetablefromcursor D/mydb: adding : Test001 TO mytable
    2019-01-09 14:15:31.623 2783-2783/ptfc.populatetablefromcursor D/mydb: adding : Test002 TO mytable
    2019-01-09 14:15:31.624 2783-2783/ptfc.populatetablefromcursor I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@453edcd
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out: 0 {
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    ID=1
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    fn=Test001
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    ln=Test001
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    e_m=email
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    pass=password
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    mobnum=xxc
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    image=null
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out: }
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out: 1 {
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    ID=2
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    fn=Test002
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    ln=Test002
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    e_m=email
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    pass=password
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    mobnum=xxc
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    image=<unprintable>
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out: }
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out: 2 {
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    ID=3
    2019-01-09 14:15:31.626 2783-2783/ptfc.populatetablefromcursor I/System.out:    fn=Test001
    2019-01-09 14:15:31.627 2783-2783/ptfc.populatetablefromcursor I/System.out:    ln=Test001
    2019-01-09 14:15:31.627 2783-2783/ptfc.populatetablefromcursor I/System.out:    e_m=email
    2019-01-09 14:15:31.627 2783-2783/ptfc.populatetablefromcursor I/System.out:    pass=password
    2019-01-09 14:15:31.627 2783-2783/ptfc.populatetablefromcursor I/System.out:    mobnum=xxc
    2019-01-09 14:15:31.627 2783-2783/ptfc.populatetablefromcursor I/System.out:    image=null
    2019-01-09 14:15:31.627 2783-2783/ptfc.populatetablefromcursor I/System.out: }
    2019-01-09 14:15:31.629 2783-2783/ptfc.populatetablefromcursor I/System.out: <<<<<
    2019-01-09 14:15:31.629 2783-2783/ptfc.populatetablefromcursor D/OUCH: Row 0 is null
    2019-01-09 14:15:31.630 2783-2783/ptfc.populatetablefromcursor D/AndroidRuntime: Shutting down VM
    2019-01-09 14:15:31.632 2783-2783/ptfc.populatetablefromcursor E/AndroidRuntime: FATAL EXCEPTION: main
        Process: ptfc.populatetablefromcursor, PID: 2783
        java.lang.RuntimeException: Unable to start activity ComponentInfo{ptfc.populatetablefromcursor/ptfc.populatetablefromcursor.MainActivity}: java.lang.NullPointerException: Attempt to get length of null array
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2914)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3049)
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1809)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loop(Looper.java:193)
            at android.app.ActivityThread.main(ActivityThread.java:6680)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
         Caused by: java.lang.NullPointerException: Attempt to get length of null array
            at ptfc.populatetablefromcursor.MainActivity.onCreate(MainActivity.java:40)
            at android.app.Activity.performCreate(Activity.java:7136)
            at android.app.Activity.performCreate(Activity.java:7127)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2894)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3049) 
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1809) 
            at android.os.Handler.dispatchMessage(Handler.java:106) 
            at android.os.Looper.loop(Looper.java:193) 
            at android.app.ActivityThread.main(ActivityThread.java:6680) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
    

    stackTrace 类似。表明 bytes.length 如果插入 null 会导致失败。

    有很多方法可以解决这个问题,例如,如果传递给 addData 方法的 ProfileImage 为空,您可以将图像列设置为默认值,同时跳过 cv.put,例如

    在数据库助手中将+ image + " BLOB ')"; 更改为+ image + " BLOB DEFAULT X'00')";

    以及 addData 方法中的以下更改:-

        if (Profileimg != null) {
            cv.put(image, Profileimg);
        }
    
    • 我不记得这将如何影响列表视图中的图像,尽管我认为它可以处理它。

    但是,根本原因是拍照会返回 null。

    此外,如果图像出现,您可能会遇到其他问题 本身很大,因为有限制(1M 最近是 2M) 具有 CursorWindow(由 Cursor 使用)可以使用的数据大小 使用 1 张图像处理超过或接近 2M 并且异常是 保证。如果有 100 万张图像,则 CursorWindow 最多只能保存 1 个图像 完全如此,因此您会遇到显示问题。

    如果图像平均在 100k 左右,那么它们可以存储在数据库中,并且 搜索可以揭示 SQlite 如何变得更强大的原因 比文件系统更高效。

    【讨论】:

    • 好的,所以我尝试了这个解决方案,它产生了一些结果,使用调试我还发现图像等于 null 这就是为什么它不起作用所以谢谢那。但我的主要问题仍然是我如何拍摄用户通过相机给我的图像并将其存储在 sqlite 数据库中
    • 另外,一个问题@MikeT 如果我不使用模拟器而是使用实际设备,结果会有所不同吗? (图片部分)
    • 模拟器会拍照吗?如果没有,它是否有允许它伪造照片的选项?我会尝试一个真正的设备。
    猜你喜欢
    • 1970-01-01
    • 2023-02-07
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 2021-09-13
    • 1970-01-01
    相关资源
    最近更新 更多