Vector
Vector

Reputation: 3235

kotlin toast in non activity class

We do not like the Toast but we included it in our DBHelper Class to know if the DB was created
YES the Logcat pointed at the Toast and the other involved Activities
First mistake not commenting out the Toast

Here is the ERROR

Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference

Here is the call made to the DBHelper

        btnSaveItemData.setOnClickListener {
        if (etItemData.text.toString().equals("")) {
            message("ENTER Item")
            etItemData.requestFocus()
            return@setOnClickListener
        }

        if (etItemFK.text.toString().equals("") || etItemFK.text.toString().toInt() == 0) {
            message("ENTER foreign key")
            etItemFK.requestFocus()
            return@setOnClickListener
        }

        val dbManager = DBHelper(this)
        val values = ContentValues()
        values.put("item", etItemData.text.toString())
        values.put("fkI",Integer.parseInt(etItemFK.text.toString()))
        if (idI == 0) {
            val mID = dbManager.insertITEM(values)

            if (mID > 0) {
                tvMsg.setTextColor(Color.RED)
                message("ADDED Item successfully")
                //Timer().schedule(800){
                    nextACTIVITY()
                //}
            } else {
                message("Failed to add Item")
            }
        }
    }

And here is the complete DBHelper with TOAST

class DBHelper(context: Context): SQLiteOpenHelper(context,DBHelper.DB_NAME,null,DBHelper.DB_VERSION) {

override fun onCreate(db: SQLiteDatabase?) {

    val CREATE_TABLE_DEPT = "CREATE TABLE ${PARENT_TABLE} ($colidD INTEGER PRIMARY KEY,$colDept TEXT,$colPFK INTEGER);"
    val CREATE_TABLE_ITEM = "CREATE TABLE ${CHILD_TABLE} ($colidI INTEGER PRIMARY KEY,$colItem TEXT,$colCFK INTEGER);"
    db!!.execSQL(CREATE_TABLE_DEPT)
    db.execSQL(CREATE_TABLE_ITEM)

    Toast.makeText(this.context,"database is created",Toast.LENGTH_LONG).show()
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    val DROP_TABLE_DEPT = "DROP TABLE IF EXISTS $PARENT_TABLE"
    val DROP_TABLE_ITEM = "DROP TABLE IF EXISTS $CHILD_TABLE"
    db!!.execSQL(DROP_TABLE_DEPT)
    db.execSQL(DROP_TABLE_ITEM)
    onCreate(db)
}

fun queryDEPT(): List<ModelParent> {
    val db = this.writableDatabase
    val parentList = ArrayList<ModelParent>()
    val selectQuery = "SELECT  * FROM ${PARENT_TABLE}"
    val cursor = db.rawQuery(selectQuery, null)
    if (cursor != null) {
        if (cursor.moveToFirst()) {
            do {
                val contact = ModelParent()
                contact.idD = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colidD)))
                contact.dept = cursor.getString(cursor.getColumnIndex(colDept))
                contact.fkD = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colPFK)))
                parentList.add(contact)
            } while (cursor.moveToNext())
        }
    }
    cursor.close()
    return parentList
}

fun queryITEM(): List<ModelChild> {
    val db = this.writableDatabase
    val childList = ArrayList<ModelChild>()
    val selectQuery = "SELECT  * FROM ${CHILD_TABLE}"
    val cursor = db.rawQuery(selectQuery, null)
    if (cursor != null) {
        if (cursor.moveToFirst()) {
            do {
                val contact = ModelChild()
                contact.idI = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colidI)))
                contact.item = cursor.getString(cursor.getColumnIndex(colItem))
                contact.fkI = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colCFK)))
                childList.add(contact)
            } while (cursor.moveToNext())
        }
    }
    cursor.close()
    return childList
}

fun insertDEPT(values: ContentValues): Long {
    val db = this.writableDatabase
    val idD = db.insert(PARENT_TABLE, null, values)
    return idD
}

fun updateDEPT(values: ContentValues, selection: String, selectionargs: Array<String>):Int{
    val db = this.writableDatabase
    val dept = db.update(PARENT_TABLE,values,selection,selectionargs)
    return dept
}

fun insertITEM(values: ContentValues): Long {
    val db = this.writableDatabase
    val idI = db.insert(CHILD_TABLE, null, values)
    return idI
}

fun updateITEM(values: ContentValues, selection: String, selectionargs: Array<String>): Int {
    val db = this.writableDatabase
    val count = db.update(CHILD_TABLE, values, selection, selectionargs)
    return count
}

fun deleteDEPT(productname: String): Boolean {
    var result = false
    val query = "SELECT * FROM $PARENT_TABLE WHERE $colDept= \"$productname\""
    val db = this.writableDatabase
    val cursor = db.rawQuery(query, null)

    if (cursor.moveToFirst()) {
        val id = Integer.parseInt(cursor.getString(0))
        db.delete(PARENT_TABLE, "$colidD = ?", arrayOf(id.toString()))
        cursor.close()
        result = true
    }
    db.close()
    return result
}

fun deleteITEM(productname: String): Boolean {
    var result = false
    val query = "SELECT * FROM $CHILD_TABLE WHERE $colItem= \"$productname\""
    val db = this.writableDatabase
    val cursor = db.rawQuery(query, null)

    if (cursor.moveToFirst()) {
        val id = Integer.parseInt(cursor.getString(0))
        db.delete(CHILD_TABLE, "$colidI = ?", arrayOf(id.toString()))
        cursor.close()
        result = true
    }
    db.close()
    return result
}

var context: Context? = null

companion object {
    private val DB_VERSION = 1
    private val DB_NAME = "Kids.db"
    private val PARENT_TABLE = "Parent"
    private val colidD = "idD"
    private val colDept = "Dept"
    private val colPFK = "fkD"
    private val CHILD_TABLE = "Child"
    private val colidI = "idI"
    private val colItem = "Item"
    private val colCFK = "fkI"
}

}

After the DBHelper writes the Data to the Database the nextActivity makes a call back to the DBHelper to queryDEPT and will display the data with the ViewParentActivity

class ViewParentActivity : AppCompatActivity() {

private var RecyclerAdapter: ParentAdapter? = null
private var recyclerView: RecyclerView? = null
private val db = DBHelper(this)
private var parentList:List<ModelParent> = ArrayList()
private var linearLayoutManager: LinearLayoutManager? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_view_parent)
    supportActionBar?.setDisplayHomeAsUpEnabled(true)

    initViews()

}// end onCreate


override fun onResume() {
    super.onResume()
    initDB()
}

// This is ONLY called when Activity is in onResume state
private fun initDB() {
    parentList = db.queryDEPT()
    if(parentList.isEmpty()){
        title = "No Records in DB"
    }else{
        title = "Parent List"
    }

    RecyclerAdapter = ParentAdapter(parentList = parentList, context = applicationContext)
    (recyclerView as RecyclerView).adapter = RecyclerAdapter
}

private fun initViews() {

    recyclerView = this.findViewById(R.id.rvParentView)
    // val etDeptFK can not be reasigned ?
    //etDeptFK = this.findViewById(R.id.etDeptFK)
    RecyclerAdapter = ParentAdapter(parentList = parentList, context = applicationContext)
    linearLayoutManager = LinearLayoutManager(applicationContext)
    (recyclerView as RecyclerView).layoutManager = linearLayoutManager!!
}

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.menu_main, menu)
    return super.onCreateOptionsMenu(menu)
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
    if (item != null) {
        when (item.itemId) {
            R.id.addNote -> {
                val intent = Intent(this, EnterParentActivity::class.java)
                intent.putExtra("FROM","N")// ADD NEW NOTE
                startActivity(intent)
            }
        }
        // CODE below manages HOME Button
        val id = item.itemId
        if (id == android.R.id.home) {
            val intent = Intent(this, EnterParentActivity::class.java)
            intent.putExtra("FROM","N")// ADD NEW NOTE
            startActivity(intent)
        }
    }
    return super.onOptionsItemSelected(item)
}

Because we are curious now
The question is how to place a Toast or some other form of notification in a non Activity Class?

Upvotes: 0

Views: 4423

Answers (3)

Shaahin
Shaahin

Reputation: 1225

If you are using Toast in Kotlin and insdie RecyclerView.Adapter, you have to call Toast like this and use instance prefix:

   class MyViewHolder (view : View) : RecyclerView.ViewHolder(view) { 

      init {
          view.setOnClickListener {
              Toast.makeText(view.context, "Your Text", Toast.LENGTH_SHORT).show()
          }
      }
}

where view is instance of View class, and context is parameter of Adapter class which implements RecyclerView

Upvotes: 0

leonardkraemer
leonardkraemer

Reputation: 6813

I suspect that this.context might be the culprit. You can not access the context of the SQLiteOpenHelper this way. You can use the following code:

//declare the context as private val property in the constructor see https://kotlinlang.org/docs/reference/classes.html
class DBHelper(private val context: Context):SQLiteOpenHelper(context,DBHelper.DB_NAME,null,DBHelper.DB_VERSION) {

    override fun onCreate(db: SQLiteDatabase?) {

    val CREATE_TABLE_DEPT = "CREATE TABLE ${DEPT_TABLE} ($colidD INTEGER PRIMARY KEY, $colDept TEXT);"
    val CREATE_TABLE_ITEM = "CREATE TABLE ${ITEM_TABLE} ($colidI INTEGER PRIMARY KEY, $colItem TEXT);"
    db!!.execSQL(CREATE_TABLE_DEPT)
    db.execSQL(CREATE_TABLE_ITEM)

    //use the context from the constructor
    Toast.makeText(context, " database is created", Toast.LENGTH_LONG).show()
}

It creates a new reference to context via the val codeword in the constructor which is in turn used for the Toast

Upvotes: 5

James_Duh
James_Duh

Reputation: 1371

This is why they invented inner class this code shows the nasty old Toast

inner class DatabaseHelper : SQLiteOpenHelper {

    var context: Context? = null

    constructor(context: Context) : super(context, dbName, null, dbVersion) {
        this.context = context
    }

    override fun onCreate(db: SQLiteDatabase?) {
        db!!.execSQL(CREATE_TABLE_SQL)
        Toast.makeText(this.context, " database is created", Toast.LENGTH_LONG).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        db!!.execSQL("Drop table IF EXISTS " + dbTable)
    }
}

Upvotes: 0

Related Questions