我在此Kotlin类中使用不正确的sqlite

问题描述 投票:-1回答:1

我最近开始学习kotlin,我正在尝试使用SQLite来实现数据库。当我尝试使用功能时,应用程序崩溃。我不知道如何找到错误日志,所以我添加了我做的功能以及在哪里实现这些功能。谢谢您的帮助。

package com.example.mrtayyab.sqlitedbkotlin

import android.content.ClipDescription
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.DatabaseUtils
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, 1) {


    companion object {

        val DATABASE_NAME = "passwords.db"
        val TABLE_NAME = "passwords_table"
        val COL_1 = "ID"
        val COL_2 = "DESCRIPTION"
        val COL_3 = "PASSWORD"
        val COL_4 = "DATE_TIME"
    }


    override fun onCreate(db: SQLiteDatabase) {

        db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_NAME(ID INTEGER PRIMARY KEY AUTOINCREMENT , DESCRIPTION  TEXT , PASSWORD TEXT , DATE_TIME INTEGER)")

    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {

        db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
        onCreate(db)

    }

    fun insertData(description: String, password: String, date_time: String): Boolean? {
        val db = this.writableDatabase
        val cv = ContentValues()
        cv.put(COL_2, description)
        cv.put(COL_3, password)
        cv.put(COL_4, date_time)
        val res = db.insert(TABLE_NAME, null, cv)
        return !res.equals(-1)
    }

    fun getData(id: String, COL_NUM: String): Cursor {
        val column = arrayOf("$COL_NUM")
        val columnValue = arrayOf("$id")
        val db = this.writableDatabase
        return db.query("$TABLE_NAME", column, "$COL_1", columnValue, null, null, null )
    }

    fun getTableCount(): Long {
        val db = this.readableDatabase
        val count = DatabaseUtils.queryNumEntries(db, TABLE_NAME)

        return count
    }
}

这里是实现它的代码

package com.example.juliaojonah_hci_outcome2_v1

import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.mrtayyab.sqlitedbkotlin.DatabaseHelper
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_main.*
import java.text.DateFormat
import java.util.*
import kotlin.collections.ArrayList

class passwords : AppCompatActivity() {

    lateinit var myDb: DatabaseHelper

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



        val dateTime = Calendar.getInstance().time

        val dateFormatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(dateTime)

        val dateTextView : TextView = findViewById(R.id.textDate2) as TextView
        dateTextView.setText(dateFormatted)

        val recyclerView = findViewById(R.id.savedPasswords) as RecyclerView

        recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)

        val counter = myDb.getTableCount()

        val passwords = ArrayList<PasswordCluster>()

        if (counter > 0) {
            for (i in 1..counter) {
                var id = i
                var description = myDb.getData(id.toString(), "COL_2")
                var password = myDb.getData(id.toString(), "COL_3")
                var dateTime = myDb.getData(id.toString(), "COL_4")

                passwords.add(PasswordCluster(description.toString(), password.toString(), dateTime.toString()))
            }
        }

/*
        passwords.add(PasswordCluster("Amazon", "56,78,90,12", "Friday"))
        passwords.add(PasswordCluster("Amazon", "56,78,90,12", "Friday"))
        passwords.add(PasswordCluster("Amazon", "56,78,90,12", "Friday"))
        passwords.add(PasswordCluster("Amazon", "56,78,90,12", "Friday"))
        passwords.add(PasswordCluster("Amazon", "56,78,90,12", "Friday"))
*/
        val adapter = CustomAdapter(passwords)

        recyclerView.adapter = adapter
    }

    fun firstActivity(view: View){
        val intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
    }
}

我在最后一段代码中使用了保存数据功能,并且它没有崩溃,但是我不知道它是否正常运行

package com.example.juliaojonah_hci_outcome2_v1

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.mrtayyab.sqlitedbkotlin.DatabaseHelper
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_main.*
import java.security.spec.PSSParameterSpec
import java.text.DateFormat
import java.util.*
import kotlin.random.Random


class MainActivity : AppCompatActivity() {

    lateinit var myDb: DatabaseHelper

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

        val dateTime = Calendar.getInstance().time

        val dateFormatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(dateTime)

        val dateTextView : TextView = findViewById(R.id.textDate) as TextView
        dateTextView.setText(dateFormatted)

        myDb = DatabaseHelper(this)
        }


    fun secondActivity(view: View){
        val intent = Intent(this, passwords::class.java)
        startActivity(intent)
    }

    fun randomise(view: View){


        val passwordSet1 = Random.nextInt(0,99)
        val passwordSet2 = Random.nextInt(0,99)
        val passwordSet3 = Random.nextInt(0,99)
        val passwordSet4 = Random.nextInt(0,99)

        val editText1 = findViewById<EditText>(R.id.password1)
        editText1.setText(passwordSet1.toString())

        val editText2 = findViewById<EditText>(R.id.password2)
        editText2.setText(passwordSet2.toString())

        val editText3 = findViewById<EditText>(R.id.password3)
        editText3.setText(passwordSet3.toString())

        val editText4 = findViewById<EditText>(R.id.password4)
        editText4.setText(passwordSet4.toString())

    }



    fun save(view: View){
        var correct = true

        val description = descriptionName.text.toString().trim()
        val password = password1.text.toString().trim() + "-" + password2.text.toString().trim() + "-" + password3.text.toString().trim() + "-" + password4.text.toString().trim()
        val dateTime = Calendar.getInstance().time
        val dateFormatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(dateTime)

        if (TextUtils.isEmpty(description)){
            descriptionName.error = "Enter description"
            correct = false
        }

        if (password == "---"){
            password1.error = "Enter password"
            password2.error = "Enter password"
            password3.error = "Enter password"
            password4.error = "Enter password"
            correct = false
        }


        var isInserted = myDb.insertData(description, password, dateFormatted)


        if (isInserted == true && correct == true){
            Toast.makeText(this, "Data Saved", Toast.LENGTH_LONG).show()
            Toast.makeText(this, isInserted.toString(), Toast.LENGTH_LONG).show()
        } else {
            Toast.makeText(this, "Data Not Saved", Toast.LENGTH_LONG).show()
        }




    }

}

这里是我尝试启动密码活动时首先出现的错误

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.juliaojonah_hci_outcome2_v1, PID: 20054
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.juliaojonah_hci_outcome2_v1/com.example.juliaojonah_hci_outcome2_v1.passwords}: kotlin.UninitializedPropertyAccessException: lateinit property myDb has not been initialized
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
     Caused by: kotlin.UninitializedPropertyAccessException: lateinit property myDb has not been initialized
        at com.example.juliaojonah_hci_outcome2_v1.passwords.onCreate(passwords.kt:42)
        at android.app.Activity.performCreate(Activity.java:6662)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6077) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 

这是我尝试运行.getData函数时发生的事情

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.juliaojonah_hci_outcome2_v1, PID: 20221
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.juliaojonah_hci_outcome2_v1/com.example.juliaojonah_hci_outcome2_v1.passwords}: kotlin.UninitializedPropertyAccessException: lateinit property myDb has not been initialized
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
     Caused by: kotlin.UninitializedPropertyAccessException: lateinit property myDb has not been initialized
        at com.example.juliaojonah_hci_outcome2_v1.passwords.onCreate(passwords.kt:51)
        at android.app.Activity.performCreate(Activity.java:6662)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6077) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 
android sqlite android-studio kotlin
1个回答
0
投票

[当我尝试使用功能时,应用程序崩溃。

lateinit property myDb has not been initialized表示您需要初始化myDB。那就是你需要包括:-

myDB = DatabaseHelper(this)
  • 在访问/使用myDB之前,也许在setContentView(R.layout.activity_main)之后

我在此Kotlin课程中使用的sqlite错误距离您不太远,但您似乎误解了查询和Android游标。简而言之,当单个查询可以返回所有这些信息,然后您可以遍历结果游标时,您正在循环查询数据库。

这里是一些问题。

getData函数中,应使用"${COL_1}=?"作为对[[query的调用的第三个参数,因为此参数是WHERE子句,而不是WHERE关键字。您实际上是在说SELECT whatever_column_is_passed FROM passwords_table WHERE x;

    x将是传递的值(1然后2然后3 ....)。正如where子句期望的是true或false,并且0为false且其他数字为正,将返回所有行。
  • 但是,关于从

    getData

  • 返回的Cursor的处理(而不是处理),您会遇到一些问题。首先,您假设表val counter = myDb.getTableCount()中的行数将等于返回的行,并且ID将被编号为1,2,3 .......最初可能是这种情况,但如果删除一行或插入失败,则序列可能不会单调递增。

    [遍历循环时,您尝试将游标分配给字符串,例如var description = myDb.getData(id.toString(), "COL_2")将导致

    description

    为光标。要解决尝试构建不喜欢Cursor的PasswordCluster的问题,您已使用CursortoString方法,这将导致使用默认对象toString方法,该方法将返回有关Cursos的详细信息,而不是预期值(描述,密码或日期时间)。建议的修复

    似乎您想通过RecyclerView将PasswordCluster的列表保存到

    passwords

    val passwords = ArrayList<PasswordCluster>())中。我建议您应该在

    DatabaseHelper

    类中具有一个将所有密码列表重新运行为ArrayList的函数,例如fun getListOfAllPasswordClusters(): ArrayList<PasswordCluster> { val rv = ArrayList<PasswordCluster>() val db = this.writableDatabase val csr = db.query(TABLE_NAME,null /* ALL columns */,null,null,null,null,null) //return db.query("$TABLE_NAME", column, "$COL_1", columnValue, null, null, null ) while (csr.moveToNext()) { rv.add( PasswordCluster( csr.getString(csr.getColumnIndex(COL_2)), csr.getString(csr.getColumnIndex(COL_3)), csr.getString(csr.getColumnIndex(COL_4)) ) ) /* NOTE ideally you should also store the id in PasswordCluster So assuming a constructor that takes Long /* id */ ,String /* description */ ,String /* password */ ,String /* date_time */ E.G. rv.add( PasswordCluster( csr.getLong(csr.getColumnIndex(COL_1)), csr.getString(csr.getColumnIndex(COL_2)), csr.getString(csr.getColumnIndex(COL_3)), csr.getString(csr.getColumnIndex(COL_4)) ) ) */ } csr.close() return rv }
      注意,我强烈建议确保PasswordCluster对象可以存储
    • id
    ,因为此值提供了访问特定行(例如更新/删除/提取单个行)的最有效方法。
      您经常会看到Int为id,这在大多数情况下可能会起作用,但是id实际上是一个Long(64位带符号整数)。因此,我建议始终将其视为Long。
  • 编码
  • AUTOINCREMENT
  • 很可能不是必需的,而且效率也不高。也许读SQLite Autoincrement
      [似乎很多人认为获取自动生成的顺序
    • id
    是必需的,不是INTEGER PRIMARY KEY本身就可以做到这一点。那么您可能会拥有:-

    class passwords : AppCompatActivity() { lateinit var myDb: DatabaseHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_passwords) val dateTime = Calendar.getInstance().time val dateFormatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(dateTime) val dateTextView : TextView = findViewById(R.id.textDate2) as TextView dateTextView.setText(dateFormatted) val recyclerView = findViewById(R.id.savedPasswords) as RecyclerView recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) val passwords = getListOfAllPasswordClusters() val adapter = CustomAdapter(passwords) recyclerView.adapter = adapter } fun firstActivity(view: View){ val intent = Intent(this, MainActivity::class.java) startActivity(intent) } }

    工作示例

    这是一个仅基于添加建议的

    getListOfAllPasswordClusters()] >> [[(注释掉的部分替换了rv.add(.........)代码,因此检索了[[id

    ]]]函数并使用以下命令的示例活动中的代码:-class MainActivity : AppCompatActivity() { lateinit var myDB: DatabaseHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myDB = DatabaseHelper(this) addSomeDataIfNone() val passwords = myDB.getListOfAllPasswordClusters() for (p: PasswordCluster in passwords) { Log.d("PASSWORDCLUSTER","ID=${p.id} Description=${p.description} password=${p.password} datetime=${p.date_time}") } } fun addSomeDataIfNone() { if (DatabaseUtils.queryNumEntries(myDB.writableDatabase,DatabaseHelper.TABLE_NAME) > 0) return myDB.insertData("Test1","password1","2019-12-01") myDB.insertData("Test2","password2","2019-12-02") myDB.insertData("Test3","password3","2019-12-03") } } 注意,为方便起见,该活动是MainActiviy而不是
    passwords
      运行和结果:-
    • 2019-12-01 07:59:58.289 D/PASSWORDCLUSTER: ID=1 Description=Test1 password=password1 datetime=2019-12-01 2019-12-01 07:59:58.289 D/PASSWORDCLUSTER: ID=2 Description=Test2 password=password2 datetime=2019-12-02 2019-12-01 07:59:58.289 D/PASSWORDCLUSTER: ID=3 Description=Test3 password=password3 datetime=2019-12-03

    简而言之,class passwords需要在其myDB = DatabaseHelper(this)方法中初始化onCreate()。您不能只是将其初始化然后在其他地方进行初始化。当新的Activity没有初始化的句柄时,将没有任何要使用的句柄。仔细观察,只有两个Activity之一初始化该句柄。
    © www.soinside.com 2019 - 2024. All rights reserved.