[英]I am using sqlite incorrectly in this kotlin class
我最近开始学习 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)
简而言之, class passwords
需要在它的onCreate()
方法中初始化myDB = DatabaseHelper(this)
。 你不能只是在某处初始化它,然后假设它会在其他地方初始化。 当新Activity
没有初始化句柄时,将没有任何句柄可以使用。 仔细一看,两个Activity
只有一个初始化了句柄。
当我尝试使用这些功能时,应用程序崩溃了。
lateinit property myDb has not been initialized
表示您需要初始化 myDB。 那就是你需要包括:-
myDB = DatabaseHelper(this)
setContentView(R.layout.activity_main)
我在这个 kotlin 类中错误地使用了 sqlite 你并不太远,但你似乎误解了查询和 Android 游标。 简而言之,当单个查询可以返回所有这些信息时,您正在循环查询数据库,然后您可以循环遍历 Cursor 的结果。
这里有一些问题。
在getData函数中,您应该使用"${COL_1}=?"
对于调用查询的第三个参数,因为此参数是WHERE子句减去 WHERE 关键字。 你实际上是在说SELECT whatever_column_is_passed FROM passwords_table WHERE x;
但是,您在处理(而不是处理)从getData返回的Cursor方面会遇到一些问题。
首先,您假设表val counter = myDb.getTableCount()
中的行数将等于返回的行数,并且 id 的编号为 1,2,3......。这最初可能是但如果一行被删除或插入失败,那么序列可能不会单调递增。
通过循环时,您试图将一个游标分配给一个字符串,例如var description = myDb.getData(id.toString(), "COL_2")
将导致description成为一个游标。 为了解决尝试构建不喜欢 Cursor 的 PasswordCluster 的问题,您使用了Cursor的toString方法,这将导致使用默认对象toString方法,该方法返回有关 Cursos 的详细信息,而不是预期值(描述、密码)或日期时间)。
看来您想从 RecyclerView 获取 PasswordCluster 的列表到密码( 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
}
那么你可以有:-
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")
}
}
运行和结果: -
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.