I'm trying to prepopulate a database, I generated the insert data but
when I run the app it gives this build error:
Caused by: org.jetbrains.org.objectweb.asm.MethodTooLargeException: Method too large:
I have a funtion like this:
RoomDatabase.Callback(){
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
val pDao = database.get().pDao()
val pLangDao = database.get().pLangDao()
applicationScope.launch {
insertPWithPLangEnglish_1_10(pDao, pLangDao)
}
}
}
private suspend fun insertPWithPLangEnglish_1_10(pDao: PDao, pLangDao: PLangDao){
var insId = pDao.insert(P(pcId = 1))
pLangDao.insert(PLang(pItemId = insId.toInt(), title = "herbert", locale = "en_US", langCode = "en"))
insId = pDao.insert(P(pcId = 1))
pLangDao.insert(PLang(pItemId = insId.toInt(), title = "others", locale = "en_US", langCode = "en"))
... and so on about 3000 more lines
}
Any idea how to solve this?
P class is the following:
#Entity(tableName = "p")
#Parcelize
data class P (
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "pid")
val pId: Int = 0,
#ColumnInfo(name = "pc_id")
val pcId: Int,
val created: Long = System.currentTimeMillis()
) : Parcelable {
}
PLang class is the following:
#Entity(tableName = "p_lang")
#Parcelize
data class PLang (
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "p_lang_id")
val pLangId: Int = 0,
#ColumnInfo(name = "p_item_id")
val pItemId: Int,
val locale: String = "",
#ColumnInfo(name = "lang_code")
val langCode: String,
val title: String,
val description: String = ""
) : Parcelable {
}
Now I'm trying another way with help of Workers, and seed database from json files.
So clearly, the Kotlin compiler is complaining because your method is too long and you should optimize it.
In order to do that you could create a global list containing all your PLang objects:
val pLangList = listOf(
PLang(title = "herbert", locale = "en_US", langCode = "en"),
PLang(title = "others", locale = "en_US", langCode = "en"),
...
)
Note that I didn't set the pItemId property, in fact, you should also change your PLang class, assigning a default value to it for convenience:
#Entity(tableName = "p_lang")
#Parcelize
data class PLang (
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "p_lang_id")
val pLangId: Int = 0,
#ColumnInfo(name = "p_item_id")
val pItemId: Int = -1, // <--- Added default value here
val locale: String = "",
#ColumnInfo(name = "lang_code")
val langCode: String,
val title: String,
val description: String = ""
) : Parcelable {
}
Now you can loop through your list and add every item with just 3 lines of code instead of ~3000:
private suspend fun insertPWithPLangEnglish_1_10(pDao: PDao, pLangDao: PLangDao)
{
for (pLang in pLangList)
{
val insId = pDao.insert(P(pcId = 1))
pLangDao.insert(PLang(pItemId = insId.toInt(), title = pLang.title, locale = pLang.locale, langCode = pLang.langCode))
}
}
Related
This is unusuall response where the name of object is the same as the object's ID and at this point I don't really know how to parse this response
"addresses": {
"163492": {
"address_id": "163492",
//more of String variables
},
"166127": {
"address_id": "166127",
//more of String variables
},
"166202": {
"address_id": "166202",
//more of String variables
}
}
this is how my Event model looks like, I'm using room database to save this response later
#Entity
data class Event(
#PrimaryKey(autoGenerate = false)
#SerializedName("id") val id: Int,
#SerializedName("title") val title: String,
#SerializedName("description") val desc: String,
#SerializedName("note") val note: String? = null,
#SerializedName("date") val dateTs: Long,
#SerializedName("begintime") val beginTime: String,
#SerializedName("enddate") val endDate: String,
#SerializedName("endtime") val endTime: String,
#SerializedName("customerid") val customerId: String? = null,
#SerializedName("address_id") val addressId: String? = null,
#SerializedName("pin") val pin: String? = null,
#SerializedName("location") val location: String? = null,
#SerializedName("customerlocation") val customerLocation: String? = null,
#field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
#SerializedName("nodes") val nodes: List<Node>? = null,
#SerializedName("closed") val closed: Int,
#SerializedName("type") val type: Int,
#SerializedName("ticketid") val ticketId: String? = null,
#SerializedName("customername") val customerName: String? = null,
#field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
#SerializedName("contacts") val contacts: List<Contacts>? = null,
#field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
#SerializedName("addresses") val addresses: List<Address>? = null,
#Embedded
#SerializedName("assignments") val assignments: Assignments? = null,
#SerializedName("lastUpdate") val lastUpdate: Long = System.currentTimeMillis()
)
everything beside the addresses part is fine cos I tested it using response with null for addresses, I tried to do deserializer for this but it appears like it don't recognise it, this is how it looks like
class EventDeserializer : JsonDeserializer<Event> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Event {
json?.asJsonObject!!.let { event ->
val nodes = mutableListOf<Node>()
val contacts = mutableListOf<Contacts>()
val addresses = mutableListOf<Address>()
val net = mutableListOf<Assignment>()
val tv = mutableListOf<Assignment>()
val assignments = Assignments(net, tv)
val netTemp = event.get("assignments").asJsonObject.get("assignments_net").asJsonArray
val tvTemp = event.get("assignments").asJsonObject.get("assignments_tv").asJsonArray
netTemp.forEach { assignment ->
assignment.asJsonObject.let {
net.add(
Assignment(
name = it.get("name").asString,
id = it.get("id").asInt
)
)
}
}
tvTemp.forEach { assignment ->
assignment.asJsonObject.let {
tv.add(
Assignment(
name = it.get("name").asString,
id = it.get("id").asInt
)
)
}
}
val nodesTemp = event.get("nodes").asJsonArray
nodesTemp.forEach { node ->
node.asJsonObject.let {
nodes.add(
Node(
id = it.get("id").asInt,
name = it.get("name").asString,
mac = it.get("mac").asString,
ip = it.get("ip").asString,
location = it.get("location").asString,
netName = it.get("netname").asString
)
)
}
}
val contactsTemp = event.get("contacts").asJsonArray
contactsTemp.forEach { contact ->
contact.asJsonObject.let {
contacts.add(
Contacts(
phone = it.get("phone").asString,
contact = it.get("contact").asString,
name = it.get("name").asString,
type = it.get("type").asString,
typeStr = it.get("typestr").asString
)
)
}
}
val addressesTemp = event.get("addresses").asJsonObject
addressesTemp?.keySet()?.let { names ->
names.forEach { name ->
addressesTemp.get(name).asJsonObject.let {
addresses.add(
Address(
id = it.get("address_id").asString,
name = it.get("location").asString
)
)
}
}
}
return Event(
id = event.get("id").asInt,
title = event.get("title").asString,
desc = event.get("description").asString,
note = event.get("note")?.asString,
dateTs = event.get("date").asLong,
beginTime = event.get("begintime").asString,
endDate = event.get("enddate").asString,
endTime = event.get("endtime").asString,
customerId = event.get("customerid")?.asString,
addressId = event.get("address_id")?.asString,
pin = event.get("pin")?.asString,
location = event.get("location")?.asString,
customerLocation = event.get("customerlocation")?.asString,
nodes = nodes,
closed = event.get("closed").asInt,
type = event.get("type").asInt,
ticketId = event.get("ticketid")?.asString,
customerName = event.get("customername")?.asString,
contacts = contacts,
addresses = addresses,
assignments = assignments
)
}
}
}
and this is how I'm creating gson factory
val gson = GsonBuilder().registerTypeAdapter(Event::class.java, EventDeserializer())
Retrofit
.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(
GsonConverterFactory.create(gson.create())
)
.callbackExecutor(Executors.newSingleThreadExecutor())
and the structure of response looks like this
Call<List<Event>>
but the list always have 1 element and this is artifact of old api that i can't change
Ok, so I figured this out, apparently your deserializer needs to be the exactly the same type as your response, so I added the interceptor that removed excess array that wrapped every response and now deserializer is being ussed as intended.
Following SQLite query (with room database library) returning null result. Which is incorrect, as you can see in the attached image.
#Query("SELECT * FROM REPOSITORY_DATABASE_TABLE WHERE item_category LIKE :key")
fun getItemByCategory(key: String) : LiveData<List<Item>>?
#Query("SELECT * FROM REPOSITORY_DATABASE_TABLE WHERE item_storage_type = :key ORDER BY item_name")
fun getItemByCategories(key: String) : LiveData<List<Item>>?
where other queries as follow returning correct result in running application as well as in Android Debug Database
#Query("SELECT * FROM REPOSITORY_DATABASE_TABLE ORDER BY item_name")
fun getAllItems() : LiveData<List<Item>>
Item Data structure:
#Entity(tableName = ApplicationConstants.REPOSITORY_DATABASE_TABLE_NAME)
data class Item(
#PrimaryKey(autoGenerate = false) #SerializedName("item_id")
var itemID: Long = 0L,
#ColumnInfo(name = "item_guid") #SerializedName("item_guid")
var itemGUID: String = "0",
#ColumnInfo(name = "item_name") #SerializedName("item_name")
var itemName: String = "Mango",
#ColumnInfo(name = "item_category") #SerializedName("item_category")
var itemCategory: String = "Fruit",
#ColumnInfo(name = "item_weight") #SerializedName("item_weight")
var itemWeight: Int = 0,
#ColumnInfo(name = "item_count") #SerializedName("item_count")
var itemCount: Int = 1,
#ColumnInfo(name = "item_image") #SerializedName("item_image")
var itemImage: String = "https://stackoverflow.com/questions/62131564/a-failure-occurred-while-
executing-org-jetbrains-kotlin-gradle-internal-kaptexec",
#ColumnInfo(name = "item_notes") #SerializedName("item_notes")
var itemNotes: String = "Sweet Yellow Mango",
#ColumnInfo(name = "item_display_quantity") #SerializedName("item_display_quantity")
var itemDisplayQuantity: String = "0",
#ColumnInfo(name = "item_storage_type") #SerializedName("item_storage_type")
var itemStorageType: String = "0",
#ColumnInfo(name = "item_creation_date") #SerializedName("item_creation_date")
var itemCreationDate: String = "0",
#ColumnInfo(name = "item_is_checked") #SerializedName("item_is_checked")
var itemIsChecked: String = "0",
#ColumnInfo(name = "item_local_status") #SerializedName("item_local_status")
var itemLocalStatus: String = "0",
#ColumnInfo(name = "item_last_added") #SerializedName("item_last_added")
var itemLastAdded: String = "0",
#ColumnInfo(name = "item_notification_status") #SerializedName("item_notification_status")
var itemNotificationStatus: String = "0",
#ColumnInfo(name = "item_priority") #SerializedName("item_priority")
var itemPriority: String = "0",
#ColumnInfo(name = "item_notification_days") #SerializedName("item_notification_days")
var itemNotificationDays: Int = 1,
#ColumnInfo(name = "item_expiry") #SerializedName("item_expiry")
var itemExpiry: String = "0",
#ColumnInfo(name = "item_synonyms") #SerializedName("item_synonyms")
#TypeConverters(Converters::class)
var itemSynonyms: List<String> = listOf("0","0")
)
Also while debugging the database with Android Debug Database I am getting correct response as shown in following image
Android Debug Database Screenshot showing correct response
Try removing the null safety operator from the return type of the query like this:
fun getItemByCategory(key: String) : LiveData<List<Item>>
And you don't have to use #SerializedName() if the SerializedName name is going to be the same as the variable itself.
And also it is very recommended if you use #PrimaryKey(autoGenerate = True) instead of false. Otherwise, you have to manually update the PrimaryKey every time you modify your table.
in this case i want to make local database when the apps on offline mode.
i want to add transaction and items transaction data to my local database.
this is my items transaction data
class ItemTransactionOffline(_bp: Double, _co: String, _cur: String, _dper: Int, _dpri: Int, _p: Int,
_qty: Int, _sp: Double, _tbp: Double, _tsp: Double, _trx: Int, _uo: String): SugarRecord() {
var base_price: Double = 0.0
var created_on: String = ""
var currency: String = ""
var discount_percent: Int = 0
var discount_price: Int = 0
var product: Int = 0
var quantity: Int = 0
var sell_price: Double = 0.0
var total_base_price: Double = 0.0
var total_sell_price: Double = 0.0
var transaction: Int = 0
var updated_on: String = ""
init {
this.sell_price = _sp
this.base_price = _bp
this.quantity = _qty
this.updated_on = _uo
this.transaction = _trx
this.total_sell_price = _tsp
this.total_base_price = _tbp
this.currency = _cur
this.discount_percent = _dper
this.discount_price = _dpri
this.created_on = _co
this.product = _p
}
constructor(): this(0.0, "", "", 0, 0, 0, 0, 0.0, 0.0, 0.0, 0, "")
}
this is my class transaction
class TransactionOffline(_idC: Int, _co: String, _cos: Any?, _del: Boolean, _ip: Boolean, _po: Any?, _store: Int,
_tp: Int, _ub: Any?, _uo: String): SugarRecord() {
var id_cashier: Int = 0
var created_on: String = ""
var customer: Any? = null
var deleted: Boolean = false
var is_paid: Boolean = false
var paid_on: Any? = null
var store: Int = 0
var total_price: Int = 0
var updated_by: Any? = null
var updated_on: String = ""
init {
this.id_cashier = _idC
this.updated_on = _uo
this.total_price = _tp
this.store = _store
this.is_paid = _ip
this.created_on = _co
this.customer = _cos
this.paid_on = _po
this.deleted = _del
this.updated_by = _ub
}
constructor(): this(0, "", null, false, false, null, 0, 0, null, "")
}
and this is my transactionHelper. in this code i want to copy data from class ItemTransactions. class ItemTransactions functions as save temporary data.
class TransactionHelper{
fun addTransaction(items: MutableList<ItemTransactions>){
val idCashier = 1
val date = SimpleDateFormat("yyyy-MM-dd ")
val datenow = Date()
val currentDate = date.format(datenow)
val trx = TransactionOffline(idCashier, currentDate, null, false, true, null, 1, Transaction.getTotalBayar().toInt(), null, currentDate)
trx.save()
val id_trx = trx.id.toInt()
Log.w("id-transaksi-local", "$id_trx")
items.forEach {
addItemTransaction(id_trx, it)
}
}
fun addItemTransaction(id: Int, item: ItemTransactions){
val itemTRX = ItemTransactionOffline(item.base_price, item.created_on, item.currency, item.discount_percent,
item.discount_price, item.product, item.quantity, item.sell_price, item.total_base_price,
item.total_sell_price, id, item.updated_on)
itemTRX.save()
}
}
i got error like this
android.database.sqlite.SQLiteException: near "TRANSACTION": syntax error (code 1): , while compiling: INSERT OR REPLACE INTO ITEM_TRANSACTION_OFFLINE(PRODUCT,CURRENCY,UPDATEDON,DISCOUNTPRICE,TRANSACTION,TOTALSELLPRICE,QUANTITY,ID,DISCOUNTPERCENT,TOTALBASEPRICE,SELLPRICE,CREATEDON,BASEPRICE) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
I am confused with that error. because i don't have class Transaction.
sorry for my poor English writing
transaction is a keyword in SQL and cannot be used as an identifier.
Consider renaming your transaction property to something else to prevent SugarORM from using it to generate incorrect SQL.
There are two tables, Task and StatisticsTask for Android room, StatisticsTask has foreign key taskId for Task.id. When I update StatisticsTask, how to tell ui query data again?
#Entity
#Parcelize
data class Task(
var name: String,
var important: Boolean = false,
var startTime: String = timeHm(),
var endTime: String = "",
var remind: String = "",
var repeat: String = "",
var repeatInterval: String = "",
var desc: String = "",
var endDate: String = "",
var startDate: String = nowOfString(),
#PrimaryKey(autoGenerate = true) var id: Int = 0
) : Parcelable {
#Ignore
var selected = false
#Ignore
var time: String? = null
#Ignore
var finished: Boolean = false
}
#Entity(foreignKeys = [ForeignKey(entity = Task::class, parentColumns = arrayOf("id"), childColumns = arrayOf("taskId"),
onDelete = CASCADE)])
#Parcelize
data class StatisticsTask(
var taskId: Int,
var date: Calendar?,
var finish: Boolean = false,
#PrimaryKey(autoGenerate = true)
var id: Int = 0
) : Parcelable {
}
//TaskViewModel.kt
fun finishTask(task: Task) {
launch {
statisticsTaskDao.updateById(task.id, !task.finished)
}
}
#Dao
interface StatisticsTaskDao {
#Query("update statisticstask set finish = :finish where taskId=:taskId and date = :date")
fun updateById(taskId: Int, finish: Boolean, date:Calendar = thisDayInitial())
}
//in my fragment
val model = ViewModelProviders.of(this)[TaskViewModel::class.java]
model.getAllOfToday().observe(this, Observer<List<Task>> {
//udpate data to adapter
})
//I want to finish this task here(in adapter)
iv_finished.setOnClickListener {
//task: first item in adapter
model.finishTask(task)
//This not work. when I finish task, how to update data again?
model.getAllOfToday()
}
This is for android-room 2.2.0-rc1, Android studio 3.5.
How to tell db query data again? I tried call this again is not working: model.getAllOfToday().observe(this#TodayFragment, Observer> {
dispatchData(it)
})
I am working on an Android application in Kotlin which integrate Firebase.
Now I want to store my data (Kotlin data class) into Firebase Database.
Data Classes:
#Parcelize
data class Trip(
val fromAddress: String,
val toAddress: String,
val fromLocation: String,
val toLocation: String,
val orderUid: String
) : Parcelable
#Parcelize
data class Order(val trip: Trip, val date: Date, var status: OrderStatus, val userUid: String) : Parcelable {
var pickUpDate: Date? = null
var dropOffDate: Date? = null
var price: Double? = null
}
Fireabase Database write operation:
fun createNewOrder(
fromAddress: String,
toAddress: String,
fromLocation: Location,
toLocation: Location
) {
val fromGeoLocation = fromLocation.convertToGeoLocation()
val toGeoLocation = toLocation.convertToGeoLocation()
val userUid = sharedPreferences[CURRENT_USER_UID_KEY, ""]!!
val orderKey = databaseReference.child(DB_ORDERS_KEY).push().key
val tripKey = databaseReference.child(DB_TRIPS_KEY).push().key
val trip = orderKey?.let { createNewTrip(fromAddress, toAddress, it) }
val order = trip?.let { Order(it, Date(), OrderStatus.PENDING, userUid) }
if (trip != null && order != null && !userUid.isNullOrEmpty()) {
ordersGeoFire.setLocation(trip.fromGeoLocation, fromGeoLocation)
ordersGeoFire.setLocation(trip.toGeoLocation, toGeoLocation)
val allData = mutableMapOf<String, Any>()
allData["/$DB_TRIPS_KEY/$tripKey"] = trip?.convertToMap()
allData["/$DB_ORDERS_KEY/$orderKey"] = order?.convertToMap()
allData["/$DB_USERS_KEY/$userUid/$DB_ORDERS_KEY/$orderKey"] = true
databaseReference.updateChildren(allData)
}
}
I received this error:
com.google.firebase.database.DatabaseException: No properties to serialize found on class kotlin.Unit
Any suggestions?
The problem in your code is that the fileds inside your Trip class are not initialized. A recommended way in which you can create your model class would be:
class Trip(
val displayName: String = "",
val email: String = "",
val photoUrl: String = "",
val userId: String = ""
)
This is only what you need. And a way to create a new object of your Trip class, would be:
val trip = Trip(displayName, email, photoUrl, userId)
It was my mistake, because I was forget to add return type in my extensions convertToMap functions. Now they look like this:
fun Trip.convertToMap(): MutableMap<String, Any> {
val map = mutableMapOf<String, Any>()
map["fromAddress"] = fromAddress
map["toAddress"] = toAddress
map["fromGeoLocation"] = fromGeoLocation
map["toGeoLocation"] = toGeoLocation
map["orderUid"] = orderUid
return map
}
And also thanks to #Alex Mamo for his answer, it helps me in my investigation.
Now my code looks like this and works fine:
#Parcelize
data class Trip(
var fromAddress: String = "",
var toAddress: String = "",
var fromGeoLocation: String = "",
var toGeoLocation: String = "",
var orderUid: String = ""
) : Parcelable
#Parcelize
data class Order(
var trip: Trip? = null,
var date: Date? = null,
var status: OrderStatus? = null,
var userUid: String = ""
) : Parcelable {
var pickUpDate: Date? = null
var dropOffDate: Date? = null
var price: Double? = null
}
fun createNewOrder(
fromAddress: String,
toAddress: String,
fromLocation: Location,
toLocation: Location
): LiveData<Order> {
orderLiveData = MutableLiveData()
orderLiveData.value = null
val userUid = sharedPreferences[CURRENT_USER_UID_KEY, ""]!!
val orderKey = databaseReference.child(DB_ORDERS_KEY).push().key
val tripKey = databaseReference.child(DB_TRIPS_KEY).push().key
val trip = orderKey?.let { createNewTrip(fromAddress, toAddress, fromLocation, toLocation, it) }
val order = trip?.let { Order(it, Date(), OrderStatus.PENDING, userUid) }
if (trip != null && order != null && !userUid.isNullOrEmpty()) {
val allData = mutableMapOf<String, Any>()
allData["/$DB_TRIPS_KEY/$tripKey"] = trip.convertToMap()
allData["/$DB_ORDERS_KEY/$orderKey"] = order.convertToMap()
allData["/$DB_USERS_KEY/$userUid/$DB_ORDERS_KEY/$orderKey"] = true
databaseReference.updateChildren(allData) { databaseError, databaseReference ->
if (databaseError == null) orderLiveData.value = order
}
}
return orderLiveData
}
Hope this will be helpful