Home > Mobile >  Kotlin SQlite: Application crashes when selecting a record
Kotlin SQlite: Application crashes when selecting a record

Time:03-22

I'm trying to implement int values into my simple sqlite program in Android studio using kotlin language.

I'm a complete beginner when it comes to Kotlin so I first made a sqlite program using only strings but now i want to use Int values.

I managed to make the values int and insert works fine, however when selecting the record, applciation crashes.

Heres the log cat.

15115-15115/com.example.sqlitedemo E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.sqlitedemo, PID: 15115 android.content.res.Resources$NotFoundException: String resource ID #0x3 at android.content.res.Resources.getText(Resources.java:444) at android.widget.TextView.setText(TextView.java:6412) at com.example.sqlitedemo.MainActivity$onCreate$4.invoke(MainActivity.kt:49)

Error kt 49 and 44 : Relates to

    adapter?.setOnClickItem {
        Toast.makeText(this,it.name,Toast.LENGTH_SHORT).show()
        //レコード更新
        edName.setText(it.name)
        edEmail.setText(it.email)
        edBuyAmount.setText(it.buyamount)
        edUseAmount.setText(it.useamount)
        std = it
    }

    at com.example.sqlitedemo.MainActivity$onCreate$4.invoke(MainActivity.kt:44)
    at com.example.sqlitedemo.StudentAdapter.onBindViewHolder$lambda-0(StudentAdapter.kt:32)

Error kt:32 relates to

override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
    val std = stdList[position]
    holder.bindView(std)
    holder.itemView.setOnClickListener{onClickItem?.invoke(std)}
    holder.btnDelete.setOnClickListener{onClickDeleteItem?.invoke(std)}
}

    at com.example.sqlitedemo.StudentAdapter.$r8$lambda$rFSStv71TK0PX1i3mffPAEhmz7s(Unknown Source:0)
    at com.example.sqlitedemo.StudentAdapter$$ExternalSyntheticLambda1.onClick(Unknown Source:4)
    at android.view.View.performClick(View.java:7448)
    at android.view.View.performClickInternal(View.java:7425)
    at android.view.View.access$3600(View.java:810)
    at android.view.View$PerformClick.run(View.java:28305)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

MainActivity class()

class MainActivity : AppCompatActivity() {

private lateinit var edName: EditText
private lateinit var edEmail: EditText
private lateinit var edBuyAmount:EditText
private lateinit var edUseAmount:EditText
private lateinit var btnAdd: Button
private lateinit var btnView: Button
private lateinit var btnUpdate: Button

private lateinit var sqLiteHelper: SQLiteHelper
private lateinit var recyclerView: RecyclerView
private  var adapter: StudentAdapter?=null
private var std:StudentModel?=null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    initView()
    initRecyclerView()
    sqLiteHelper= SQLiteHelper(this)
    //Show recycler view
    val stdList = sqLiteHelper.getAllStudent()
    Log.e("ok","${stdList.size}")

    adapter?.addItems(stdList)

    btnAdd.setOnClickListener{ addStudent()}
    btnView.setOnClickListener{getStudents()}
    btnUpdate.setOnClickListener{updateStudent()}
    adapter?.setOnClickItem {
        Toast.makeText(this,it.name,Toast.LENGTH_SHORT).show()
        //data update
        edName.setText(it.name)
        edEmail.setText(it.email)
        edBuyAmount.setText(it.buyamount)
        edUseAmount.setText(it.useamount)
        std = it
    }
    adapter?.setOnClickDeleteItem{
        deleteStudent(it.id)

    }
}

private fun deleteStudent(id:Int){
    val builder = AlertDialog.Builder(this)
    builder.setMessage("do you want to delete?")
    builder.setCancelable(true)
    builder.setNegativeButton("no"){dialog, _ ->
        dialog.dismiss()
    }
    builder.setPositiveButton("yes"){dialog, _ ->
        sqLiteHelper.deleteStudentById(id)
        getStudents()
        dialog.dismiss()
    }

    val alert = builder.create()
    alert.show()
}

private fun updateStudent(){
    val name = edName.text.toString()
    val email = edEmail.text.toString()
    val buyAmount = edBuyAmount.text.toString().toInt()
    val useAmount = edUseAmount.text.toString().toInt()
    //Check record not changed
    if(name == std?.name && email == std?.email && buyAmount == std?.buyamount && useAmount == std?.useamount){
        Toast.makeText(this,"Data wasnt updated",Toast.LENGTH_SHORT).show()
        return
    }

    if(std == null) return
    val std = StudentModel(id=std!!.id,name = name,email = email, buyamount = buyAmount, useamount = useAmount )
    val status = sqLiteHelper.updateStudent(std)
    if(status > -1){
        clearEditText()
        getStudents()
    }else{
        Toast.makeText(this,"error",Toast.LENGTH_SHORT).show()
    }


}
private fun getStudents(){
    val stdList = sqLiteHelper.getAllStudent()
    Log.e("ok","${stdList.size}")

    adapter?.addItems(stdList)
}
private fun addStudent(){
    val name = edName.text.toString()
    val email = edEmail.text.toString()
    val buyAmount = edBuyAmount.text.toString().toInt()
    val useAmount = edUseAmount.text.toString().toInt()

    if(name.isEmpty()||email.isEmpty()|| buyAmount.toString().isEmpty() ||useAmount.toString().isEmpty()){
        Toast.makeText(this,"enter data",Toast.LENGTH_SHORT).show()
    }else{
        val std = StudentModel(name = name, email=email, buyamount=buyAmount, useamount=useAmount)
        val status = sqLiteHelper.insertStudent(std)
        //Check Insert success or not success
        if(status > -2){
            Toast.makeText(this,"added data",Toast.LENGTH_SHORT).show()
            clearEditText()
        }else{
            Toast.makeText(this,"data is not found。",Toast.LENGTH_SHORT).show()
        }
    }
}
private fun clearEditText(){
    edName.setText("")
    edEmail.setText("")
    edBuyAmount.setText("")
    edUseAmount.setText("")
    edName.requestFocus()
}
private fun initRecyclerView(){
    recyclerView.layoutManager=LinearLayoutManager(this)
    adapter = StudentAdapter()
    recyclerView.adapter=adapter
}
private fun initView(){
    edName = findViewById(R.id.edName)
    edEmail = findViewById(R.id.edEmail)
    edBuyAmount=findViewById(R.id.edBuyAmount)
    edUseAmount=findViewById(R.id.edUseAmount)
    btnAdd = findViewById(R.id.btnAdd)
    btnView = findViewById(R.id.btnView)
    btnUpdate=findViewById(R.id.btnUpdate)
    recyclerView=findViewById(R.id.recyclerView)

}

}

Record adapater class

class StudentAdapter: RecyclerView.Adapter<StudentAdapter.StudentViewHolder>() { private var stdList: ArrayList<StudentModel> = ArrayList() private var onClickItem: ((StudentModel) -> Unit)?=null private var onClickDeleteItem: ((StudentModel) -> Unit)?=null

fun addItems(items: ArrayList<StudentModel>){
    this.stdList=items
    notifyDataSetChanged()
}
fun setOnClickItem(callback:(StudentModel)->Unit){
    this.onClickItem = callback
}
fun setOnClickDeleteItem(callback: (StudentModel) -> Unit){
    this.onClickDeleteItem = callback
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)= StudentViewHolder (
    LayoutInflater.from(parent.context).inflate(R.layout.card_items_rec,parent,false)
)

override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
    val std = stdList[position]
    holder.bindView(std)
    holder.itemView.setOnClickListener{onClickItem?.invoke(std)}
    holder.btnDelete.setOnClickListener{onClickDeleteItem?.invoke(std)}
}

override fun getItemCount(): Int {
    return stdList.size
}
class StudentViewHolder(var view: View):RecyclerView.ViewHolder(view){
    private var id = view.findViewById<TextView>(R.id.tvId)
    private var name = view.findViewById<TextView>(R.id.tvName)
    private var email = view.findViewById<TextView>(R.id.tvEmail)
    private var buyAmount = view.findViewById<TextView>(R.id.tvBuyAmount)
    private var useAmount = view.findViewById<TextView>(R.id.tvUseAmount)
    var btnDelete = view.findViewById<TextView>(R.id.deleteBtn)

    fun bindView(std:StudentModel){
        id.text = std.id.toString()
        name.text = std.name
        email.text = std.email
        buyAmount.text = std.buyamount.toString()
        useAmount.text = std.useamount.toString()
    }
}

}

StudentDatabase class

class SQLiteHelper(context:Context):SQLiteOpenHelper(context,DATABASE_NAME,null,DATABASE_VERSION){ companion object{ private const val DATABASE_VERSION =1 private const val DATABASE_NAME ="student.db" private const val TBL_STUDENT = "tblRecords" private const val ID ="[id]" private const val NAME ="[name]" private const val EMAIL ="[email]" private const val BUYAMOUNT ="[buyamount]" private const val USEAMOUNT ="[useamount]" }

override fun onCreate(db: SQLiteDatabase?) {
    val createTblStudent = ("CREATE TABLE "  TBL_STUDENT   "("
              ID   " INTEGER PRIMARY KEY,"  NAME  " TEXT," 
            EMAIL  " TEXT,"  BUYAMOUNT  " INTEGER,"  USEAMOUNT  " INTEGER" ")")
    db?.execSQL(createTblStudent)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    db!!.execSQL("DROP TABLE IF EXISTS $TBL_STUDENT")
    onCreate(db)
}
fun insertStudent(std: StudentModel): Long {
    val db = this.writableDatabase
    val contentValues = ContentValues()
    contentValues.put(ID, std.id)
    contentValues.put(NAME, std.name)
    contentValues.put(EMAIL, std.email)
    contentValues.put(BUYAMOUNT,std.buyamount)
    contentValues.put(USEAMOUNT,std.useamount)

    val success = db.insert(TBL_STUDENT,null,contentValues)
    db.close()
    return success
}
fun getAllStudent():ArrayList<StudentModel>{
    val stdList: ArrayList<StudentModel> = ArrayList()
    val selectQuery = "SELECT * FROM $TBL_STUDENT"
    val db = this.readableDatabase

    val cursor: Cursor?
    try {
        cursor = db.rawQuery(selectQuery,null)
    }catch (e:Exception){
        e.printStackTrace()
        db.execSQL(selectQuery)
        return ArrayList()
    }
    var id: Int
    var name: String
    var email: String
    var buyamount: Int
    var useamount: Int
    if(cursor.moveToFirst()){
        do{
            id = cursor.getInt(cursor.getColumnIndexOrThrow("id"))
            name = cursor.getString(cursor.getColumnIndexOrThrow("name"))
            email = cursor.getString(cursor.getColumnIndexOrThrow("email"))
            buyamount = cursor.getString(cursor.getColumnIndexOrThrow("buyamount")).toInt()
            useamount = cursor.getString(cursor.getColumnIndexOrThrow("useamount")).toInt()
            val std = StudentModel(id = id,name = name,email=email,buyamount=buyamount,useamount=useamount)
            stdList.add(std)
        }while(cursor.moveToNext())
    }
    return stdList
}
fun updateStudent(std: StudentModel):Int{
    val db = this.writableDatabase
    val contentValues = ContentValues()
    contentValues.put(ID,std.id)
    contentValues.put(NAME,std.name)
    contentValues.put(EMAIL,std.email)
    contentValues.put(BUYAMOUNT, std.buyamount)
    contentValues.put(USEAMOUNT,std.useamount)

    val success = db.update(TBL_STUDENT,contentValues,"id=" std.id,null)
    db.close()
    return success
}
fun deleteStudentById(id:Int):Int{
    val db = this.writableDatabase
    val contentValues = ContentValues()

    contentValues.put(ID,id)

    val success = db.delete(TBL_STUDENT,"id=$id",null)
    db.close()
    return success
}

}

Student model class

package com.example.sqlitedemo import java.util.* data class StudentModel( var id: Int=getAutoId(), var name: String = "", var email: String = "", var buyamount: Int = 0, var useamount: Int=0 ){ companion object{ fun getAutoId():Int{ val random = Random() return random.nextInt(100) } } }

I tried everything but still no clue where i went wrong. Any advice or solutions?

Apolgoies for the inconsistent code layout, im new to stack overflow.

CodePudding user response:

The problem is the setText method of TextView has multiple implementations,

public final void setText(@StringRes int resid) {
     // ...
}

public final void setText(CharSequence text) {
     // ...
}

And the buyamount and useamount of your student model are int type.

So, when you call setText of TextView, the system will call the setText(Int) instead of setText(CharSequence).

The setText(Int) will use the int parameter as resources id to get string resource. When the resource of given id not found, the exception will be thrown.

To fix this problem, try to convert the buyamount and useamount to string before set them to the TextView. For example,

edBuyAmount.setText(""   it.buyamount)
edUseAmount.setText(""   it.useamount)
  • Related