我最近开始学习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)
[当我尝试使用功能时,应用程序崩溃。
lateinit property myDb has not been initialized
表示您需要初始化myDB。那就是你需要包括:-
myDB = DatabaseHelper(this)
setContentView(R.layout.activity_main)
之后我在此Kotlin课程中使用的sqlite错误距离您不太远,但您似乎误解了查询和Android游标。简而言之,当单个查询可以返回所有这些信息,然后您可以遍历结果游标时,您正在循环查询数据库。
这里是一些问题。
在getData函数中,应使用"${COL_1}=?"
作为对[[query的调用的第三个参数,因为此参数是WHERE子句,而不是WHERE关键字。您实际上是在说SELECT whatever_column_is_passed FROM passwords_table WHERE x;
getData
val counter = myDb.getTableCount()
中的行数将等于返回的行,并且ID将被编号为1,2,3 .......最初可能是这种情况,但如果删除一行或插入失败,则序列可能不会单调递增。[遍历循环时,您尝试将游标分配给字符串,例如var description = myDb.getData(id.toString(), "COL_2")
将导致
description
为光标。要解决尝试构建不喜欢Cursor的PasswordCluster的问题,您已使用Cursor的toString方法,这将导致使用默认对象toString方法,该方法将返回有关Cursos的详细信息,而不是预期值(描述,密码或日期时间)。建议的修复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
}
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
之一初始化该句柄。