Lateinit variable not initialized error but got initialized (android) - java

I know that sounds weird.
So in my MainActivity am declaring an Array of the object SongInfo which looks like this:
class SongInfo {
lateinit var title: String
lateinit var contentId: String
lateinit var filepath: String
}
This is how I am declaring the Array in my MainActivity:
lateinit var songInfo: Array<SongInfo?>
So, now when I press a button, the listener of this button executes this:
searchButton.setOnClickListener {
val cursor = contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
arrayOf(
"_id",
"_data",
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DURATION
),
"is_music == 1",
null, null
)
songInfo = arrayOfNulls(cursor!!.count)
for (index in songInfo.indices) {
songInfo[index] = SongInfo()
Log.d(tag, "searchButton: $index")
}
adapter = listMusicService.listMusic(cursor)
adapter.notifyDataSetChanged()
}
The ListMusicService class looks like this:
class ListMusicService(val context: Context, private var adapter: ArrayAdapter<Any>) {
private val tag = "MusicShare/ListMusicService"
fun listMusic(cursor: Cursor): ArrayAdapter<Any> {
val activity = MainActivity()
adapter.clear()
val songInfo = arrayOfNulls<SongInfo>(cursor.count)
var duration: Double
var index = 0
while (cursor.moveToNext()) {
duration = ((cursor.getDouble(4) / 600).roundToInt() / 100).toDouble()
adapter.add(cursor.getString(3) + ": " + cursor.getString(2) + " (" + duration + ")")
val filepath = File(cursor.getString(1))
Log.d(tag, "searchMusic: writing songInfo")
songInfo[index] = SongInfo()
songInfo[index]!!.title = filepath.name
songInfo[index]!!.filepath = filepath.absolutePath
activity.songInfo[index]!!.filepath = filepath.absolutePath
songInfo[index]!!.contentId = cursor.getString(0)
index++
}
return adapter
}
}
Pressing the searchButton now causes a kotlin.UninitializedPropertyAccessException: lateinit property songInfo has not been initialized.
But I don't understand why because in the listener method of searchButton I'm initializing every object of the array. Does anybody know why this happens and maybe what goes wrong?
EDIT: Creating the ListMusicService:
val listMusicService = ListMusicService(this, adapter)

You are creating a new object of MainActivity
val activity = MainActivity()
which is just an empty object, instead you need to pass this as an instance of MainAcitiy to listMusic method and use it.
ListMusicService class already taking a context object so seems like you are passing the activity's instance (no code about it), use the existing adapter instance of MainAcitivty.
// somewhere in main activity
val listMusicService = ListMusicService(this, adapter)
// inside searchButton.setOnClickListener
adapter = listMusicService.listMusic(cursor)
adapter.notifyDataSetChanged()
In ListMusicService
fun listMusic(cursor: Cursor): ArrayAdapter<Any> {
adapter.clear()
val songInfo = arrayOfNulls<SongInfo>(cursor.count)
var duration: Double
var index = 0
while (cursor.moveToNext()) {
duration = ((cursor.getDouble(4) / 600).roundToInt() / 100).toDouble()
adapter.add(cursor.getString(3) + ": " + cursor.getString(2) + " (" + duration + ")")
val filepath = File(cursor.getString(1))
Log.d(tag, "searchMusic: writing songInfo")
songInfo[index] = SongInfo()
songInfo[index]!!.title = filepath.name
songInfo[index]!!.filepath = filepath.absolutePath
activity.songInfo[index]!!.filepath = filepath.absolutePath
songInfo[index]!!.contentId = cursor.getString(0)
index++
}
return adapter
}

Related

An annotation argument must be a compile-time constant when trying to convert java enum

I tried to convert a java file to kotlin file but i'm getting this error : An annotation argument must be a compile-time constant
#StringDef(
BillingEnum.ALL,
BillingEnum.PAID,
BillingEnum.PENDING,
BillingEnum.OVERDUE,
BillingEnum.OPEN,
BillingEnum.DELETED
)
annotation class BillingEnum {
companion object {
var ALL = ""
var PAID = "paid"
var PENDING = "pending"
var OVERDUE = "overdue"
var OPEN = "open"
var DELETED = "deleted"
}
}
Before it looked like this:
#StringDef({
BillingEnum.ALL,
BillingEnum.PAID,
BillingEnum.PENDING,
BillingEnum.OVERDUE,
BillingEnum.OPEN,
BillingEnum.DELETED
})
public #interface BillingEnum {
String ALL = "";
String PAID = "paid";
String PENDING = "pending";
String OVERDUE = "overdue";
String OPEN = "open";
String DELETED = "deleted";
}
You must write
annotation class BillingEnum {
companion object {
const val ALL = ""
const val PAID = "paid"
const val PENDING = "pending"
const val OVERDUE = "overdue"
const val OPEN = "open"
const val DELETED = "deleted"
}
}

Can't get media metadata compat string

I'm creating a kotlin app. I have an issue with mediaMetadataCompat. Maybe I have to put data to extras? I put data like this
audios = allAudios!!.map { audio ->
MediaMetadataCompat.Builder()
.putString(METADATA_KEY_WRITER, audio.writer._id)
.putString(METADATA_KEY_ARTIST, audio.writer.name)
.putString(METADATA_KEY_DISPLAY_SUBTITLE, audio.writer.name)
.putString(METADATA_KEY_MEDIA_ID, audio._id)
.putString(METADATA_KEY_TITLE, audio.title)
.putString(METADATA_KEY_DISPLAY_TITLE, audio.title)
.putString(METADATA_KEY_DISPLAY_ICON_URI, audio.writer.image)
.putString(METADATA_KEY_DATE, audio.createdAt)
.putString(METADATA_KEY_MEDIA_URI, audio.filePath)
.putString(METADATA_KEY_DISPLAY_DESCRIPTION, audio.description)
.build()
}
Get it like this
fun MediaMetadataCompat.toAudio(): Audio? {
return let {
Audio(
_id = it.description.mediaId ?: "",
title = it.description.title.toString(),
filePath = it.description.mediaUri.toString(),
description = it.description.description.toString(),
writer = User(
_id = it.description.extras?.getString("writerId").toString(),
name = it.description.subtitle.toString(),
image = it.description.iconUri.toString()
),
tags = listOf("Shit"),
listened = 1,
language = "en",
isForKids = false,
duration = 70,
createdAt = "2020:01:01"
)
}
}
It only gives my title, icon_uri, media_uri and media_id
Sharing a small part of my code:
Below is building object of MediaMetaDataCompat. I am adding couple of data there and have used in different parts of app.
var media = MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, data.id.toString())
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, data.artist_name)
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, data.title)
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, data.audio_path)
.putString(MediaMetadataCompat.METADATA_KEY_DATE, data.track_year)
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, data.image_path)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, data.duration.toLong())
.build()
mediaItem is object of MediaMetadataCompat and that is how I am getting values of the fields which was added to object.
mediaItem is object of MediaMetadataCompat
var artist = mediaItem.bundle.getString(MediaMetadataCompat.METADATA_KEY_ARTIST)!!
var title = mediaItem.bundle.getString(MediaMetadataCompat.METADATA_KEY_TITLE)!!
var duration = mediaItem.bundle.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)!!
var icon = mediaItem.bundle.getString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI)!!

How to show Realm Data base results to an edit text?

so I'm new to realm data base and I'm trying to show the data that the user wrote throw an Edit text and show it in a Textview..
My realm class
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
#RealmClass
open class GoodStudents : RealmObject(){
#PrimaryKey
var id: Long = 0
var name : String? = null
var grade : Int? = null
}
Main activity code
Realm.init(this)
val convig = RealmConfiguration.Builder()
.name("GoodStudents").build()
val realm = Realm.getInstance(convig)
realm.beginTransaction()
count = realm.where(GoodStudents::class.java).findAll().size
val goodStudents = realm.createObject(GoodStudents::class.java, count+1)
goodStudents.name = name.text.toString()
goodStudents.grade
realm.commitTransaction()
val readData = realm.where(GoodStudents::class.java).findAll()
saveButton.setOnClickListener {
Toast.makeText(this,"Data is saved", Toast.LENGTH_LONG).show()
var text = text.text
readData.forEach { save ->
save.name = text as String?
}
}
P.C. Java code is acceptable..
so I found out that writing this code will work
saveButton.setOnClickListener {
val convig = RealmConfiguration.Builder()
.name("GoodStudents").build()
val realm = Realm.getInstance(convig)
realm.beginTransaction()
count = realm.where(GoodStudents::class.java).findAll().size
val goodStudents = realm.createObject(GoodStudents::class.java, count+1)
goodStudents.name = name.text.toString()
goodStudents.grade = grade.text.toString().toInt()
val readData = realm.where(GoodStudents::class.java).findAll()
readData.forEach { save ->
text.text = "" + save.name + ": " + goodStudents.grade
}
realm.commitTransaction()
}

Convert a Map to an Object in Kotlin

Hello guys I have a simple question ,
I have a Map full of element and I want to convert It in my Object , let me show you some code :
Here is my Object :
class Bundle(map: Map<String, Any>) {
var version: String?
var app: String?
var countries: ArrayList<Any>?
var currency: ArrayList<Any>?
var force: Boolean?
var name: String?
var service: ArrayList<Any>?
var money: Int?
init {
version= null
app= null
countries= arrayListOf()
currency= arrayListOf<Any>()
force= true
name = ""
service= arrayListOf<Any>()
money= 0
}
}
And there is the Map that i want to convert:
fun getBundle() {
var db = FirebaseFirestore.getInstance()
val docRef = db.collection("aa").document("bb")
docRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val document = task.result
if (document.exists()) {
Log.d("Doc", "DocumentSnapshot data: " + document.data!!)
// Here i want to take (document.data!!) and convert it to my Bundle class
} else {
Log.d("NO doc", "No such document")
}
} else {
Log.d("ERROR", "get failed with ", task.exception)
}
}
}
Thank you !
Ok I found the solution
I transformed my Bundle class in a data class :
data class Bundle(
var version: String? = null,
var app: String? = null,
var countries: ArrayList<Any> = arrayListOf(),
var currency: HashMap<String, Any> = hashMapOf(),
var force: Boolean = false,
var name: String? = null,
var service: ArrayList<Any> = arrayListOf(),
var money: Int = 0
)
And then I simply added this on my method , where I want to convert my Map to my Bundle Object :
val myObject = document.toObject(Bundle::class.java)

Kotlin Database Error CursorIndexOutOfBoundsException

This is error, it says index out of bounds, but i couldn't how can i solve it, there are some Turkish words but they aren't important, i think:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.burhanozen.nothesaplama, PID: 26919
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.burhanozen.nothesaplama/com.example.burhanozen.nothesaplama.MainActivity}: android.database.CursorIndexOutOfBoundsException: Index 1 requested, with a size of 1
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at ........
I was trying to store some kind of student information. I have these errors, and I share codes below.
This is my MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)
val fab = findViewById(R.id.fab) as FloatingActionButton
fab.setOnClickListener {
val intent = Intent(this#MainActivity,NotEkrani::class.java)
startActivity(intent) }
val studentsArray = ArrayList<String>()
val arrayAdapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,studentsArray)
listView.adapter= arrayAdapter
try{
val myDatabase = this.openOrCreateDatabase("student", Context.MODE_PRIVATE,null)
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS students (isim TEXT," +
" dersbir TEXT, dersbirkredi TEXT, dersbirort TEXT," +
" dersiki TEXT, dersikikredi TEXT, dersikiort TEXT) ")
val cursor = myDatabase.rawQuery("select * from students",null)
val nameIx = cursor.getColumnIndex("isim")
val dersbirIx = cursor.getColumnIndex("dersbir")
val dersbirkrediIx = cursor.getColumnIndex("dersbirkredi")
val dersbirortIx = cursor.getColumnIndex("dersbirort")
val dersikiIx = cursor.getColumnIndex("dersiki")
val dersikikrediIx = cursor.getColumnIndex("dersikikredi")
val dersikiortIx = cursor.getColumnIndex("dersikiort")
cursor.moveToNext()
while (cursor != null){
studentsArray.add(cursor.getString(nameIx))
studentsArray.add(cursor.getString(dersbirIx))
studentsArray.add(cursor.getString(dersbirkrediIx))
studentsArray.add(cursor.getString(dersbirortIx))
studentsArray.add(cursor.getString(dersikiIx))
studentsArray.add(cursor.getString(dersikikrediIx))
studentsArray.add(cursor.getString(dersikiortIx))
cursor.moveToNext()
arrayAdapter.notifyDataSetChanged()
}
while (cursor!=null){
cursor!!.close()
}
}catch (e:SQLException){
}
And this is my second Activity Page, i couldn't any error here, but may be this can help. I wrote database codes here.
fun kaydet(view:View){
val isim = isim.text.toString()
val dersbir = dersbir.text.toString()
val dersbirkredi = dersbirkredi.text.toString()
val dersbirort = dersbirort.text.toString()
val dersiki = dersiki.text.toString()
val dersikikredi = dersikikredi.text.toString()
val dersikiort = dersikiort.text.toString()
try {
val myDatabase = openOrCreateDatabase("student", Context.MODE_PRIVATE,null)
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS students (isim TEXT," +
" dersbir TEXT, dersbirkredi TEXT, dersbirort TEXT," +
" dersiki TEXT, dersikikredi TEXT, dersikiort TEXT) ")
val sqlString = "INSERT INTO students (isim,dersbir,dersbirkredi,dersbirort,dersiki,dersikikredi,dersikiort) VALUES(?,?,?,?,?,?,?)"
val statement = myDatabase.compileStatement(sqlString)
statement.bindString(1,isim)
statement.bindString(2,dersbir)
statement.bindString(3,dersbirkredi)
statement.bindString(4,dersbirort)
statement.bindString(5,dersiki)
statement.bindString(6,dersikikredi)
statement.bindString(7,dersikiort)
statement.execute()
}catch (e:SQLException){
}
val intent = Intent(this,MainActivity::class.java)
startActivity(intent)
}
Change your while loop to look like this:
while (cursor.moveToNext()){
studentsArray.add(cursor.getString(nameIx))
...
}
(Remove all the other cursor.moveToNext() from your code)
You are checking for cursor != null in your while loop condition, but it won't become null after you read all the rows from cursor.
In the above code, cursor.moveToNext returns true if there is a row next. Otherwise returns false and the loop terminates.
And, just noticed, you should change this from,
while (cursor!=null){
cursor!!.close()
}
to an if check:
if (cursor!=null){
cursor.close()
}
Or, as Todd suggested in the comments, you can use the Higher order function use which automatically closes the cursor, which is simlar to Java 7 try-with-resources.
cursor.use {
while (cursor.moveToNext()){
studentsArray.add(cursor.getString(nameIx))
...
}
}
You are getting this error because your cursor size is 1. There is only one record in your database. But you are querying database more than 1 time. That is the reason of your Error.
First of all your complete code of execution is wrong.
You are creating a database in your activity. If you do you can't manage your database properly and efficiently.
First, you have to create a SqliteOpenHelper database in a separate class. Then you have to create a table there. Then write helper methods there to get and insert values from it.
Your database class should be like the below example.
class DbHelper(context: Context) : SQLiteOpenHelper(context, "example.db", null, 4) {
val TAG = javaClass<DbHelper>().getSimpleName()
val TABLE = "logs"
companion object {
public val ID: String = "_id"
public val TIMESTAMP: String = "TIMESTAMP"
public val TEXT: String = "TEXT"
}
val DATABASE_CREATE =
"CREATE TABLE if not exists " + TABLE + " (" +
"${ID} integer PRIMARY KEY autoincrement," +
"${TIMESTAMP} integer," +
"${TEXT} text"+
")"
fun log(text: String) {
val values = ContentValues()
values.put(TEXT, text)
values.put(TIMESTAMP, System.currentTimeMillis())
getWritableDatabase().insert(TABLE, null, values);
}
fun getLogs() : Cursor {
return getReadableDatabase()
.query(TABLE, arrayOf(ID, TIMESTAMP, TEXT), null, null, null, null, null);
}
override fun onCreate(db: SQLiteDatabase) {
Log.d(TAG, "Creating: " + DATABASE_CREATE);
db.execSQL(DATABASE_CREATE)
}
override fun onUpgrade(p0: SQLiteDatabase, p1: Int, p2: Int) {
}
}
Since you are using Kotin database is very easy with Anko-Sqlite. By this library storing and retrieving data from the database is so easy. You can check it here.
https://github.com/Kotlin/anko/wiki/Anko-SQLite#using-anko-sqlite-in-your-project

Categories