简体   繁体   English

如何在Android Studio中从Sqlite数据库插入和检索图像

[英]How to insert and retrieve image from Sqlite database in Android Studio

I'm attempting to take some data from a user including a picture taken by the camera and then insert that into the DB (thumbnail) and then retrieve it to be viewed later on. 我正在尝试从用户那里获取一些数据,包括相机拍摄的照片,然后将其插入DB(缩略图)中,然后检索它以便以后查看。 1- I used this and this 1-我用这个 和这个

But i still get an error 但是我仍然会出错 在这张图片中

line 45 mentioned in this error is here: 此错误中提到的第45行在这里: 这是错误

and this is the OnclickListener that responds to the user's input. 这是响应用户输入的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");
            }

        }
    });

And finally, this is the part where it inserts inside the database which I think has the actual error with regards to the image being inserted. 最后,这是它插入数据库内部的部分,对于要插入的图像,我认为这存在实际错误。

 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;
    }
}

I got these 2 functions online so I think it's important to put them here but I think they've something to do with the error but I can't be sure 我在线获得了这两个函数,所以我认为将它们放在这里很重要,但是我认为它们与错误有关,但是我不确定

    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();
    }
}

The messsage indicates that bytes is null. 消息表明字节为空。 The documentation for getBlob states :- getBlob的文档指出:-

The result and whether this method throws an exception when the column value is null or the column type is not a blob type is implementation-defined. 结果以及此方法是否在列值为null或列类型不是blob类型时引发异常是实现定义的。

As such I believe that getBlob is returning a null and therefore that the likliehood is that nulls are getting inserted. 因此,我相信getBlob返回的是null,因此,最有可能的是插入了null。

Consider the following based upon your DatabaseHelper :- 根据您的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);
    }

This adds two rows the first with null as the byte[] (image), the second has a valid albeit it short byte[]. 这将两行相加,第一行以null作为byte [](图像),第二行具有有效值,尽管它是短byte []。

The rows are inserted without issue. 插入行没有问题。

The Data is extract without issue. 数据提取没有问题。

However the log will contain the following :- 但是,日志将包含以下内容:

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) 

The stackTrace is similar. stackTrace类似。 showing that bytes.length results in the failure if a null is inserted. 显示如果插入null则bytes.length导致失败。

There are many ways this could be fixed for example you could set the image column to have a DEFAULT value along with skipping the cv.put if the ProfileImage passed to the addData method is null eg 有很多方法可以解决此问题,例如,如果传递给cv.put方法的ProfileImage为null,则可以将image列设置为具有DEFAULT值,同时跳过cv.put

in the Database helper change + image + " BLOB ')"; 在数据库助手中更改+ image + " BLOB ')"; to + image + " BLOB DEFAULT X'00')"; + image + " BLOB DEFAULT X'00')";

along with the following change in the addData method :- 以及addData方法中的以下更改:-

    if (Profileimg != null) {
        cv.put(image, Profileimg);
    }
  • I can't recall how this will affect the image in the listview, although I think it handles it. 我不记得这会如何影响列表视图中的图像,尽管我认为它可以处理它。

However, the root cause will be that the picture taking will be returning a null. 但是,根本原因是拍照将返回null。

Additionally you will likely encounter other issues if the images themselves are large as there are limitations (1M more recently 2M) with the size of data that a CursorWindow (used by a Cursor) can handle exceed or get close to 2M with 1 image and an exception is guaranteed. 此外,如果图片本身很大,则可能会遇到其他问题,因为对于CursorWindow(由Cursor使用)可以处理的数据大小存在限制(最近为1M,现在为2M)超过或接近2张图片和1张图片。保证例外。 With 1M images a CursorWindow will hold 1 at the most if at all so you'd expect display issues. 使用1M图像时,CursorWindow最多可以容纳1,因此您可能会期望显示问题。

If images average around 100k then they can be stored in the DB and a search could reveal the reasoning behind how SQlite can be more efficient than a file system. 如果图像平均约为100k,则可以将它们存储在数据库中,而搜索可以揭示SQlite如何比文件系统更有效的背后原因。

This is an alternative solution if you don't want to use blob. 如果您不想使用Blob,则这是另一种解决方案。 You can implement is as follow, 您可以实现如下,

  • Convert the image bitmap into base64 and save it as text in sqlite. 将图像位图转换为base64并将其另存为sqlite中的文本。
  • When you retrieve, convert that base64 into bitmap and show it in ImageView. 检索时,将该base64转换为位图并在ImageView中显示。

For the conversion code, please refer it here 有关转换代码,请在此处参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM