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(); } } 
12
  • 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. Commented Jan 8, 2019 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. Commented Jan 9, 2019 at 0: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. Commented Jan 9, 2019 at 0: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 Commented Jan 9, 2019 at 1: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. Commented Jan 9, 2019 at 1:17

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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
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)
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.
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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.