I am trying to set the float value to an edit text. For this I am using a binding adapter like this below.
#BindingAdapter("android:text")
#JvmStatic
fun setAmount(editText: EditText, currency: Float?) {
if (currency!= null && currency!=0.0f) {
editText.setText(""+Math.round(currency))
}else{
editText.setText("")
}
}
Model Class
class OpportunityModel : BaseObservable(), Serializable {
var accountName = ""
var accountGuid: String? = null
var amount = 0.0
var potentialAmount:Float = 0.0f
get() = field
set(value) {field=value}
var contactPersonName = ""
var fieldOne = ""
var fieldTwo = ""
var fieldThree = ""
var fieldFour = ""
var fieldFive = ""
var opportunityName = ""
var opportunityGuid: String? = null
var opportunityRating = 0
var opportunityReasonGuid: String? = null
var opportunityIntStatus = 2
var opportunityDispStatus = ""
var opportunityNotAvailable = false
var genericFieldUI: GenericFieldDto? = null
#SerializedName("expDateOfClosure")
var dateForServer: String? = null
var expDate = ""
var contactPersonNameGuid: String? = null
var listOfAccountContact = ArrayList<AccountContactPersonModel>()
var listOfReasonMaster = ArrayList<ReasonMasterDto>()}
This shows the value properly in the edit text but when this value is added to the model class via data binding, it gets converted to scientific notation and is showing values like 1E+07. How can I stop this conversion to scientific notation ?
You can use String.format, like
#BindingAdapter("android:text")
#JvmStatic
fun setAmount(editText: EditText, currency: Float?) {
if (currency!= null && currency!=0.0f) {
editText.setText(String.format("%.8f", currency))
}else{
editText.setText("")
}
}
Related
I have an object that I wrote to a file and now I want to take that string I get from the file to turn it back into an object for me to use.
Object class:
#Serializable
class DrinkItem {
#SerializedName("strAlcoholic")
val alcoholic: String? = null
#SerializedName("strIngredient1")
val ingredient1: String? = null
#SerializedName("strIngredient10")
val ingredient10: String? = null
#SerializedName("strIngredient11")
val ingredient11: String? = null
#SerializedName("strIngredient12")
val ingredient12: String? = null
#SerializedName("strIngredient13")
val ingredient13: String? = null
#SerializedName("strIngredient14")
val ingredient14: String? = null
#SerializedName("strIngredient15")
val ingredient15: String? = null
#SerializedName("strIngredient2")
val ingredient2: String? = null
#SerializedName("strIngredient3")
val ingredient3: String? = null
#SerializedName("strIngredient4")
val ingredient4: String? = null
#SerializedName("strIngredient5")
val ingredient5: String? = null
#SerializedName("strIngredient6")
val ingredient6: String? = null
#SerializedName("strIngredient7")
val ingredient7: String? = null
#SerializedName("strIngredient8")
val ingredient8: String? = null
#SerializedName("strIngredient9")
val ingredient9: String? = null
#SerializedName("strInstructions")
val instructions: String? = null
#SerializedName("strMeasure1")
val measurement1: String? = null
#SerializedName("strMeasure10")
val measurement10: String? = null
#SerializedName("strMeasure11")
val measurement11: String? = null
#SerializedName("strMeasure12")
val measurement12: String? = null
#SerializedName("strMeasure13")
val measurement13: String? = null
#SerializedName("strMeasure14")
val measurement14: String? = null
#SerializedName("strMeasure15")
val measurement15: String? = null
#SerializedName("strMeasure2")
val measurement2: String? = null
#SerializedName("strMeasure3")
val measurement3: String? = null
#SerializedName("strMeasure4")
val measurement4: String? = null
#SerializedName("strMeasure5")
val measurement5: String? = null
#SerializedName("strMeasure6")
val measurement6: String? = null
#SerializedName("strMeasure7")
val measurement7: String? = null
#SerializedName("strMeasure8")
val measurement8: String? = null
#SerializedName("strMeasure9")
val measurement9: String? = null
#SerializedName("strDrink")
val name: String? = null
#SerializedName("strDrinkThumb")
val thumbnail: String? = null
}
I use this function to write the object to a file:
private fun writeToFile(fileName: String, byteArray: ByteArray){
val lineSeparator: String = System.getProperty("line.separator") as String
// File
val path = context!!.filesDir
val directory = File(path, "LET")
directory.mkdirs()
val file = File(directory, fileName)
//append drink to file
FileOutputStream(file, true).use {
it.write(byteArray)
it.write(lineSeparator.toByteArray())
}
}
After the function is done with the object it is turned into this string:
{"alcoholic":"Alcoholic","ingredient1":"Apricot brandy","ingredient2":"Triple sec","ingredient3":"Lime","ingredient4":"Lime","instructions":"Shake all ingredients (except lime wedge) with ice and strain into a cocktail glass. Add the wedge of lime and serve.","measurement1":"1 oz ","measurement2":"1 oz ","measurement3":"Juice of 1 ","measurement4":"1 ","name":"After Dinner Cocktail","thumbnail":"https://www.thecocktaildb.com/images/media/drink/vtytxq1483387578.jpg"}
Is there a function or library that would help me turn a string of an object into said object?
Are you using library to convert your DrinkItem to the outputting JSON String? Seems that the keys in your JSON String do not match with what you have named in #SerializedName().
You can use the Gson library to handle JSON String and Object conversion.
For example, if you have the same DrinkItem class, you can convert your DrinkItem into JSON String as following:
// Define DrinkItem and set some of the attributes
val drinkItemTest = DrinkItem()
drinkItemTest.alcoholic = "Alcohol One"
drinkItemTest.ingredient1 = "Ingredient One"
// Use Gson library to convert Object to JSON String
val drinkItemTestString = Gson().toJson(drinkItemTest)
println(drinkItemTestString)
Output
{"strAlcoholic":"Alcohol One","strIngredient1":"Ingredient One"}
And to convert your JSON String back to DrinkItem, you can do something like this:
// Read the whole JSON String from your file here
val drinkItemString = "{\"strAlcoholic\":\"Alcohol One\",\"strIngredient1\":\"Ingredient One\"}"
// And make use of Gson library to convert your JSON String into DrinkItem Object
val drinkItem = Gson().fromJson(drinkItemString, DrinkItem::class.java)
I have a JSON string that I need to converted to data class object in Kotlin, the problem is that there is a field (details) that can have a different structure depending of the value of another field like this
val jsonString1 = "{'name': 'Juan', 'phase': 'step1', 'details': { 'name': 'product 1' }}"
val jsonString2 = "{'name': 'Juan', 'phase': 'step2', 'details': { 'position': 10 }}"
now I have something like
data class Customer(
var name: String? = null
var phase: String? = null
var details: Details? = null
)
data class Details(
var name: String? = null
)
data class Details2(
var position: Int? = null
)
now with gson I know I can
Gson().fromJson(jsonString1, Customer::class.java)
I want to be able to automatically use the right data class depending on the value of the phase field, I know I can create an adapterFactory, but I can't figure out how, an in kotlin is worse
I was reading this post
http://anakinfoxe.com/blog/2016/02/01/gson-typeadapter-and-typeadapterfactory/
and I'm pretty sure is the way to go, but I can't quite get it
Yep, it's pretty easy to write such adapter. I've slightly changed your example:
data class Customer(
var name: String? = null,
var phase: String? = null,
var details: Details? = null
)
sealed class Details {
data class Details1(var name: String? = null) : Details()
data class Details2(var position: Int? = null) : Details()
}
class CustomerDeserializer : JsonDeserializer<Customer> {
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): Customer {
val customerObject = json.asJsonObject
val detailsObject = customerObject.getAsJsonObject("details")
val details = if (detailsObject.has("name")) {
Details.Details1(detailsObject.get("name").asString)
} else {
Details.Details2(detailsObject.get("position").asInt)
}
return Customer(
name = customerObject.get("name").asString,
phase = customerObject.get("phase").asString,
details = details
)
}
}
fun main() {
val gson = GsonBuilder()
.registerTypeAdapter(Customer::class.java, CustomerDeserializer())
.create()
println(gson.fromJson(jsonString1, Customer::class.java))
println(gson.fromJson(jsonString2, Customer::class.java))
}
data class Customer(
var name: String? = null
var phase: String? = null
var details: Details? = null
)
data class Details(
var name: String? = null
var position: Int? = null
)
Define Details class in this way
Gson().fromJson(jsonString1, Customer::class.java)
return a Customer either name is null or position is null
I am trying to use a data class but I can't figure out how to save the data properly.
I have created a data class:
data class SavedValue( var currentValue:String, var previousValue:String = "")
What I want is each time I am want to save a new currentValue, the already saved value for current is copy to previousValue and the new currentValue overwrite the currentValue field.
Thanks for the help
A data class in Kotlin is not supposed to provide such functionalities, as they are designed to hold data.
You could just use a simple class.
Nevertheless you can achieve what you want (with or without a data class), but you will have to move currentValue inside the class and use a setter (and a getter).
In its place use a private property like _currentValue:
data class SavedValue(private var _currentValue: String, var previousValue: String = "") {
var currentValue: String
get() = _currentValue
set(value) {
previousValue = _currentValue
_currentValue = value
}
}
This code:
val sv = SavedValue("abc")
println("currentValue = ${sv.currentValue} and previousValue = ${sv.previousValue}")
will print:
currentValue = abc and previousValue =
and this:
sv.currentValue = "ABC"
println("currentValue = ${sv.currentValue} and previousValue = ${sv.previousValue}")
will print:
currentValue = ABC and previousValue = abc
Also, I think that you need previousValue as a read only property, right?
So move it too inside the class and make its setter private:
data class SavedValue(private var _currentValue: String) {
var _previousValue: String = ""
var currentValue: String
get() = _currentValue
set(value) {
previousValue = _currentValue
_currentValue = value
}
var previousValue: String
get() = _previousValue
private set(value) {
_previousValue = value
}
}
What you are trying to achieve isn't straight forward using data class. Instead, you can use POJO class and use custom setter and getter.
class SavedValue(currentValue: String, previousValue: String) {
private var _currentValue: String = currentValue
private var _previousValue: String = previousValue
var currentValue: String
get() {
return _currentValue
}
set(value) {
_previousValue = _currentValue
_currentValue = value
}
override fun toString(): String {
return "SavedValue(_currentValue='$_currentValue',
_previousValue='$_previousValue')"
}
}
The first solution works fine but if you do not want the third field just to hold the current value you can do:
data class SavedValue(var previousValue: String = "") {
var currentValue: String = ""
set(value) {
if (field != value) previousValue = field
field = value
}
}
E.g.
val savedValue = SavedValue()
savedValue.currentValue = "initial value"
println("current: ${savedValue.currentValue} - previous: ${savedValue.previousValue}")
savedValue.currentValue = "second value"
println("current: ${savedValue.currentValue} - previous: ${savedValue.previousValue}")
savedValue.currentValue = "third value"
println("current: ${savedValue.currentValue} - previous: ${savedValue.previousValue}")
Outputs:
I/System.out: current: initial value - previous:
I/System.out: current: second value - previous: initial value
I/System.out: current: third value - previous: second value
Or if you want the non-mutable previousValue you'll need the third field:
data class SavedValue(private var _previousValue: String = "") {
var currentValue: String = ""
set(value) {
if (field != value) _previousValue = field
field = value
}
val previousValue: String
get() = _previousValue
}
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
I am performing many to many relationship in Realm and i am trying to read objects in Realm but i ain't getting Realm Results. This is how i'm storing objects in Realm.
fun addMessage(message : Message?,ref_id : String?){
Realm.getDefaultInstance().use {realm ->
realm.executeTransaction {realm ->
val num = realm.where<Messages>().max("auto_index")
var nextVal : Int ?= null
if (num == null){
nextVal = 1
}else{
nextVal = num.toInt() + 1
}
val msg = Messages()
msg.messageId = message?.message_uid
msg.body = message?.body
msg.isCheck = message?.isCheck
msg.auto_index = nextVal
val messa = realm.where<MessageRef>().equalTo("messageRefId",ref_id).findFirst()
if (messa != null){
messa.messages?.add(msg)
}
else {
val messageRef = MessageRef()
messageRef.messageRefId = ref_id
messageRef.messages = RealmList<Messages>()
messageRef.messages?.add(msg)
realm.copyToRealmOrUpdate(messageRef)
}
realm.copyToRealmOrUpdate(msg)
}
}
}
That's how i'm reading objects from database.
fun getAllMessages (realm : Realm?,messageRefId : String?)=
realm?.where<MessageRef>()?.equalTo("messageRefId",messageRefId)?.findFirst()
?.messages?.sort("auto_index")
}
Below is my MessageRef model.
open class MessageRef : RealmObject() {
#Required
#PrimaryKey
var messageRefId : String ?= null
var messages : RealmList<Messages> ?= null
}
Below is my Messages Model.
open class Messages : RealmObject(){
#Required
#PrimaryKey
var messageId : String ?= null
#Required
var auto_index : Int ?= null
#Required
var body : String ?= null
#Required
var isCheck : String ?= null
}
But I'm not getting any results. I debug the code and found that objects are successfully storing but not able to read.Below is my activity code.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_chat_page)
initialize()
message_ref_id = intent?.getStringExtra("conversation_id")
toolbar_name?.text = name
messageList = realmMessageController?.getAllMessages(realm,message_ref_id)
}
Please tell me anybody why i ain't getting result.
ORIGINAL ANSWER: You are getting the following error
IllegalArgumentException: 'value' is not a valid managed object
And that's because you're trying to add an unmanaged object to a managed RealmObject's RealmList
You can use copyToRealmOrUpdate() to get a managed proxy of the thing you are saving:
messageRef.messages?.add(realm.copyToRealmOrUpdate(Messages().apply {
messageId = message?.message_uid
isCheck = message?.isCheck
auto_index = nextValue
}))
EDIT: to do what you want, you just need to check against the managed RealmObject if it's already in the list.
val managed = realm.copyToRealmOrUpdate(Messages().apply {
messageId = message?.message_uid
isCheck = message?.isCheck
auto_index = nextValue
})
if(messageRef.messages?.contains(managed) == false) {
messageRef.messages?.add(managed)
}
EDIT2: For your query, you need
open class Messages : RealmObject(){
#Required
#PrimaryKey
var messageId : String ?= null
#Required
var auto_index : Int ?= null
#Required
var body : String ?= null
#Required
var isCheck : String ?= null
}
#field:LinkingObjects("messages")
val messageRefs : RealmResults<MessageRef>? = null
Then
realm.where<Messages>()
.equalTo("messageRefs.messageRefId", messageRefId)
.sort("auto_index")
.findAll()