1

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. 1- I used this and this

But i still get an error in this image

line 45 mentioned in this error is here: This is the error

and this is the OnclickListener that responds to the user's input.

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();
    }
}
Ye Min Htut
  • 2,904
  • 15
  • 28
Zyzzx
  • 45
  • 1
  • 11
  • Please don't post screenshots of code, XML, or logcat output. Please post all text as text. Also, it's generally a bad idea to store images in a database. Save them as files in storage, and store their paths in the database instead. – Mike M. Jan 08 '19 at 23:56
  • @MikeM. yes, I gathered as much from other sources but given the time constraint, this is the way I must go about it. – Zyzzx Jan 09 '19 at 00:02
  • the problem is how you retrieve the image because you put the image in String list, try it to retrieve and place it in list view. to insert image to database. convert bitmap to byte[] to retrieve from database. convert byte[] to bitmap. – jhayjhay Jan 09 '19 at 00:38
  • better save image name to database and save image in storage it will be easy to call from database just make sure of path – Ashish Jan 09 '19 at 01:16
  • @jhayjhay regarding the part where I insert the picture I do convert it to byte[] and you will find that in the last picture. regarding retrieving the image I'm not sure what you mean but I am trying to place it in a list view and in the 2 other SO question i posted it succeded like that. – Zyzzx Jan 09 '19 at 01:17
  • @Ashish yes, I gathered as much from other sources that I linked but given the time constraint, this is the way I must go about it. but if u can please send some guides, tutorials or anything related on how I can "save image name to database and save image in storage it will be easy to call from database just make sure of path" and ill check them out. – Zyzzx Jan 09 '19 at 01:18
  • let me give you code – Ashish Jan 09 '19 at 01:18
  • *but given the time constraint*, but posting screens shots and not copied and pasted code/stack traces you are very likely **extending** the time as many will not even attempt to consider answering, others may just comment further expending your valuable time. Mentioning time constraints too will divert potential solutions being provided. – MikeT Jan 09 '19 at 02:19
  • @MikeT i received a comment alot like yours and i removed all screenshot the only 2 left are of the error and the of the line of which the error mentions and/or refers to. and yes im well aware of the time that will be expended but i only post questions on SO as a last resort. so if you have any idea on how i can improve my question please do tell. it wont hurt if more people were to answer my question. And the code you are looking at **IS** copied and pasted by the way. And I also only put the code relevant to the issuewhich i beleive is actually the right thing to do according to SO rules. – Zyzzx Jan 09 '19 at 02:28
  • I already said a) do not post screenshots of code or stack traces, copy and paste the them and b) do not mention your time it will annoy some (better explained in help). P.S. I am looking at this but I believe your issue is that you are inserting null data. – MikeT Jan 09 '19 at 02:34
  • Try 1) delete the App's data (if you can afford to lose data (which you should be able to do so when developing)) then 2) Adding a breakpoint on the line `cv.put(image, Profileimg);` in addData. Running in debug mode and when the breakpoint is reached look for the ProfileImage variable what is it's value?. – MikeT Jan 09 '19 at 02:44
  • @Zyzzx you did. but in retrieving your photo.. you place it in List. try to make Constuctors. – jhayjhay Jan 09 '19 at 06:42

2 Answers2

2

The messsage indicates that bytes is null. The documentation for getBlob states :-

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.

As such I believe that getBlob is returning a null and therefore that the likliehood is that nulls are getting inserted.

Consider the following based upon your 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[].

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. showing that bytes.length results in the failure if a null is inserted.

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 e.g.

in the Database helper change + image + " BLOB ')"; to + image + " BLOB DEFAULT X'00')";

along with the following change in the addData method :-

    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.

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. With 1M images a CursorWindow will hold 1 at the most if at all so you'd expect display issues.

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.

MikeT
  • 51,415
  • 16
  • 49
  • 68
  • ok so i tried this solution out and it yielded some results and using debug i also found out that the image is equal to **null** and thats why it wouldnt work so thanks for that. But my main issue still stands which is how do i take the image that the user gives me via camera and store it in the sqlite database – Zyzzx Jan 09 '19 at 04:06
  • also, a question @MikeT would the results be any different if I didn't use an emulator but an actual device? (for the image part) – Zyzzx Jan 09 '19 at 04:23
  • Does the emulator take pictures? If not, does it have options that allow it to fake taking a picture? I'd try a real device. – MikeT Jan 09 '19 at 04:33
0

This is an alternative solution if you don't want to use blob. You can implement is as follow,

  • Convert the image bitmap into base64 and save it as text in sqlite.
  • When you retrieve, convert that base64 into bitmap and show it in ImageView.

For the conversion code, please refer it here

Ye Min Htut
  • 2,904
  • 15
  • 28