【发布时间】:2020-12-04 13:58:01
【问题描述】:
当我尝试启动我的程序时,我收到以下消息:
2020-12-04 14:45:19.691 12612-12612/de.thm.ap.recordclean E/AndroidRuntime: FATAL EXCEPTION: main
Process: de.thm.ap.recordclean, PID: 12612
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.reflect.InvocationTargetException
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)
Caused by: java.io.InvalidClassException: de.thm.ap.recordclean.model.Record; local class incompatible: stream classdesc serialVersionUID = -4375446896736906014, local class serialVersionUID = 9183845667872741158
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:624)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1713)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1594)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1872)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at java.util.ArrayList.readObject(ArrayList.java:791)
at java.lang.reflect.Method.invoke(Native Method)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1066)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2013)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at de.thm.ap.recordclean.persistence.RecordDAO.initRecords(RecordDAO.kt:83)
at de.thm.ap.recordclean.persistence.RecordDAO.<init>(RecordDAO.kt:11)
at de.thm.ap.recordclean.persistence.RecordsActivity.onStart(RecordsActivity.kt:33)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8024)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
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)
我的 RecordDao 看起来像这样:
class RecordDAO(private val ctx: Context) {
private var nextId = 0
private val records = initRecords()
fun findAll(): List<Record> = records.toList()
fun findById(id: Int): Record? {
var record: Record? = Record()
records.forEach { if( it.id== id) record = it }
return record
}
/**
* Ersetzt das übergebene [Record] Objekt mit einem bereits gespeicherten [Record] Objekt mit gleicher id.
*
* @param record
* @return true = update ok, false = kein [Record] Objekt mit gleicher id im Speicher gefunden
*/
fun update(record: Record): Boolean {
var existing = false
records.forEach {
if(it.id == record.id){
val index= records.indexOf(it)
records[index] = record
existing = true
}
}
saveRecords()
return existing
}
/**
* Persistiert das übergebene [Record] Objekt und liefert die neue id zurück.
* (Seiteneffekte: record.id = nextId; nextId += 1 )
*
* @param record
* @return neue record id
*/
fun persist(record: Record): Int {
record.id = nextId
records.add(record)
saveRecords()
return record.id!!
}
/**
* Löscht das übergebene [Record] Objekt anhand der id aus dem Speicher.
*
* @param record
* @return true = ok, false = kein [Record] Objekt mit gleicher id im Speicher gefunden
*/
fun delete(record: Record): Boolean {
var existing = false
if(records.contains(record)){
val index:Int = records.indexOf(record)
records.removeAt(index)
existing = true
}
saveRecords()
return existing
}
private fun initRecords(): MutableList<Record> {
val records = mutableListOf<Record>()
val f = ctx.getFileStreamPath(FILE_NAME)
if (f.exists()) {
ctx.openFileInput(FILE_NAME).use { fin ->
ObjectInputStream(fin).readObject().let { obj ->
records.addAll(obj as MutableList<Record>)
// init next id
if (records.size > 0) {
nextId += 1
}
}
}
}
return records;
}
private fun saveRecords() {
ctx.openFileOutput(FILE_NAME, Context.MODE_PRIVATE)
.use { ObjectOutputStream(it).writeObject(records) }
}
companion object {
private const val FILE_NAME = "records.obj"
}
我的 RecordsActivity 是这样的:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_records)
this.recordListView.emptyView = recordListEmptyView
}
override fun onStart() {
super.onStart()
val outputRecords = RecordDAO(this).findAll().map {
"${it.moduleName} ${it.moduleNum} (%${it.noteInProzent} ${it.creditPoints}crp)"
}
val allRecords = RecordDAO(this).findAll()
val adapter = ArrayAdapter(this,android.R.layout.simple_list_item_activated_1,outputRecords)
this.recordListView.adapter = adapter
recordListView.setOnItemClickListener { parent, view, position, id ->
val record: Record = allRecords[position]
intent = Intent(this,EditFormActivity::class.java)
intent.putExtra("record",record)
startActivity(intent)
}
with(recordListView) {
val checkedRecords = ArrayList<Record>()
choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
setMultiChoiceModeListener(object: AbsListView.MultiChoiceModeListener {
override fun onItemCheckedStateChanged(mode: ActionMode?, position: Int, id: Long, checked: Boolean) {
if(checked) checkedRecords.add(allRecords[position])
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
val menuInflater = menuInflater
menuInflater.inflate(R.menu.list_view_contextual_menu,menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
//val emailSubject = "Meine Leistungen $size "
return when(item.itemId) {
R.id.delete_item -> {
AlertDialog.Builder(this@RecordsActivity)
.setTitle("Delete list items")
.setMessage("Are you sure you want to delete the selected items?")
.setNegativeButton("No",null)
.setPositiveButton("Yes") { _:DialogInterface, _:Int ->
checkedRecords.forEach {
RecordDAO(this@RecordsActivity).delete(it)
}
val i = Intent(this@RecordsActivity,RecordsActivity::class.java)
startActivity(i)
}
.show()
true
}
else -> { println("no")
true}
}
}
override fun onDestroyActionMode(mode: ActionMode?) {
}
})
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.records,menu)
return true
}
fun count50s() : Int {
var count = 0
val records = RecordDAO(this).findAll()
records.forEach{
if(it.funfzigProzentGewichtung) count++
}
return count
}
fun countCrp() : Int {
var crp = 0
val records = RecordDAO(this).findAll()
records.forEach {
crp += it.creditPoints
}
return crp
}
fun getDurchschnitt() : Int {
var value = 0
var summe = 0
val records = RecordDAO(this).findAll()
records.forEach {
summe += it.noteInProzent
}
value = summe / records.size
return value
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when(item.itemId) {
R.id.action_add -> {
val i = Intent(this, RecordFormActivity::class.java)
startActivity(i)
true
}
R.id.action_stats -> {
val size = RecordDAO(this).findAll().size
val count = count50s()
val crp = countCrp()
val ziel = 180-crp
val durchSchnitt = getDurchschnitt()
val message =
"""
Leistungen $size
50% Leistungen $count
Summe Crp $crp
Crp bis Ziel $ziel
Durchschnitt $durchSchnitt
"""
AlertDialog.Builder(this)
.setTitle("Statistik")
.setMessage(message)
.show()
true
}
else -> super.onOptionsItemSelected(item)
}
该程序之前已启动,我不太确定我更改了什么,因此它不再运行。我在玩 size 变量,但我想我把它改回原来的样子,我删除了表单 xml 文件中一个未使用的 TextView,就是这样我想如果我改变了其他东西,我就记不起来了
编辑:记录类
package de.thm.ap.recordclean.model
import java.io.Serializable
data class Record(var moduleName:String = "Betriebssysteme", var moduleNum: String = "CS2033",
var semester:Int = 2000, var creditPoints:Int = 6,
var noteInProzent:Int = 50,
var funfzigProzentGewichtung:Boolean = true) : Serializable {
var id: Int? = null
}
【问题讨论】:
-
您发布的课程似乎与错误中的课程不匹配。这条线似乎很重要。引起:java.io.InvalidClassException:de.thm.ap.recordclean.model.Record;本地类不兼容:stream classdesc serialVersionUID = -4375446896736906014,本地类serialVersionUID = 9183845667872741158 但我不知道recordclean是什么。
-
也发布了我的 Record 课程
标签: android kotlin android-intent