Problem passing a variable from one activity to another (Kotlin / Android) - kotlin

This is driving me nuts.
I am taking a number of variables and passing them in a bundle to the same activity. All of the variables are passing through just fine - except for one. It is extremely odd to me because there are 7 other variables that are being assigned and passed in the same manner with no problems.
I know that the variable is being set to the proper value. The problem appears to be either when the variable is being passed or when it is being received. Or something I have no idea about...
As I said, I am bundling the variables and then calling the same activity, which then receives the variables. There is another activity that is used to bring this one up - and the variable passing has the same problem with the exact same variable.
Here is where I bundle the variables
var intentNext= Intent(this#PositionActivityLeft, PositionActivityLeft::class.java)
val bundle = Bundle()
bundle.putBoolean("confirmChoices", confirmChoices)
bundle.putString("gameType", gameType)
bundle.putInt("smallBlind", smallBlind)
bundle.putInt("bigBlind", bigBlind)
bundle.putInt("buyIn", buyIn)
bundle.putInt("handsPerHour", handsPerHour)
bundle.putString("venue", venue)
bundle.putString("location", location)
bundle.putString("venueType", venueType)
bundle.putInt("numSession", numSession)
bundle.putInt("numSessionHands", numSessionHands)
bundle.putInt("stackSize", stackSize)
bundle.putInt("numVillains", numVillainsCount)
bundle.putString("heroPosition", heroPosition)
bundle.putString("villain1Position", villain1Position)
bundle.putString("villain2Position", villain2Position)
bundle.putString("villain3Position", villain3Position)
bundle.putString("Villain4Position", villain4Position)
bundle.putString("villain5Position", villain5Position)
bundle.putString("villain6Position", villain6Position)
bundle.putString("villain7Position", villain7Position)
bundle.putString("villain8Position", villain8Position)
intentNext.putExtras(bundle)
startActivity(intentNext)
overridePendingTransition(0,0)
and here is where I read them in:
class PositionActivityLeft : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_position_left)
// other variable declarations
val bundle: Bundle? = intent.extras
val confirmChoices = bundle!!.getBoolean("confirmChoices")
val gameType = bundle.getString("gameType")
val smallBlind = bundle.getInt("smallBlind")
val bigBlind = bundle.getInt("bigBlind")
val buyIn = bundle.getInt("buyIn")
val handsPerHour = bundle.getInt("handPerHour")
val venue = bundle.getString("venue")
val location = bundle.getString("location")
val venueType = bundle.getString("venueType")
val numSession = bundle.getInt("numSession")
val numSessionHands = bundle.getInt("numSessionHands")
val stackSize = bundle.getInt("stackSize")
val numVillains = bundle.getInt("numVillains")
var heroPosition = bundle.getString("heroPosition")
var villain1Position = bundle.getString("villain1Position","_")
var villain2Position = bundle.getString("villain2Position","_")
var villain3Position = bundle.getString("villain3Position","_")
var villain4Position = bundle.getString("villain4Position","_")
var villain5Position = bundle.getString("villain5Position","_")
var villain6Position = bundle.getString("villain6Position","_")
var villain7Position = bundle.getString("villain7Position","_")
var villain8Position = bundle.getString("villain8Position","_")
for all of the villainPosition variables, I have a default value ("_"). All of the variables pass the intended value of the variable except for villain4Position - it always goes to the default.
I have some code that shows me that the variable is being set properly prior to bundling and sending. It is the reading that isn't getting through. I have tried changing the variable name, changing the location of the line (moving it up or down) and it's always the same result.
I had originally set up a mutablelistOf for the villainPosition variable which allowed me to do a number of things with much less code, but the 4th variable in the list (index 3) kept having problems. I thought it might have been in how I was iterating things or something, so I went and modified the program to explicitly callout all 8 variables and work with them individually. And the result was exactly the same - the 4th variable is not passing from one activity to another.

The problem is a typo
The value is stored in the bundle using the key (with an uppercase "V").
"Villain4Position"
while (with a lowercase "v") is the key used to retrieve the value from the bundle.
"villain4Position"
To fix this, you should ensure that the bundle key used to retrieve the value matches the one used to put it. Try changing the key used to retrieve the value for
"villain4Position" to "Villain4Position"

Related

Convert String into list of Pairs: Kotlin

Is there an easier approach to convert an Intellij IDEA environment variable into a list of Tuples?
My environment variable for Intellij is
GROCERY_LIST=[("egg", "dairy"),("chicken", "meat"),("apple", "fruit")]
The environment variable gets accessed into Kotlin file as String.
val g_list = System.getenv("GROCERY_LIST")
Ideally I'd like to iterate over g_list, first element being ("egg", "dairy") and so on.
And then ("egg", "dairy") is a tuple/pair
I have tried to split g_list by comma that's NOT inside quotes i.e
val splitted_list = g_list.split(",(?=(?:[^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*\$)".toRegex()).toTypedArray()
this gives me first element as [("egg", second element as "dairy")] and so on.
Also created a data class and tried to map the string into data class using jacksonObjectMapper following this link:
val mapper = jacksonObjectMapper()
val g_list = System.getenv("GROCERY_LIST")
val myList: List<Shopping> = mapper.readValue(g_list)
data class Shopping(val a: String, val b: String)
You can create a regular expression to match all strings in your environmental variable.
Regex::findAll()
Then loop through the strings while creating a list of Shopping objects.
// Raw data set.
val groceryList: String = "[(\"egg\", \"dairy\"),(\"chicken\", \"meat\"),(\"apple\", \"fruit\")]"
// Build regular expression.
val regex = Regex("\"([\\s\\S]+?)\"")
val matchResult = regex.findAll(groceryList)
val iterator = matchResult.iterator()
// Create a List of `Shopping` objects.
var first: String = "";
var second: String = "";
val shoppingList = mutableListOf<Shopping>()
var i = 0;
while (iterator.hasNext()) {
val value = iterator.next().value;
if (i % 2 == 0) {
first = value;
} else {
second = value;
shoppingList.add(Shopping(first, second))
first = ""
second = ""
}
i++
}
// Print Shopping List.
for (s in shoppingList) {
println(s)
}
// Output.
/*
Shopping(a="egg", b="dairy")
Shopping(a="chicken", b="meat")
Shopping(a="apple", b="fruit")
*/
data class Shopping(val a: String, val b: String)
Never a good idea to use regex to match parenthesis.
I would suggest a step-by-step approach:
You could first match the name and the value by
(\w+)=(.*)
There you get the name in group 1 and the value in group 2 without caring about any subsequent = characters that might appear in the value.
If you then want to split the value, I would get rid of start and end parenthesis first by matching by
(?<=\[\().*(?=\)\])
(or simply cut off the first and last two characters of the string, if it is always given it starts with [( and ends in )])
Then get the single list entries from splitting by
\),\(
(take care that the split operation also takes a regex, so you have to escape it)
And for each list entry you could split that simply by
,\s*
or, if you want the quote character to be removed, use a match with
\"(.*)\",\s*\"(.*)\"
where group 1 contains the key (left of equals sign) and group 2 the value (right of equals sign)

Kotlin: class instance variable value-parameter error

First post - New to Kotlin so beginner-learner. Please be gentle if my terminology is not quite up to scratch yet!
I'm attempting to call a parameter that i've declared in a secondary constructor within my main function variable but it doesnt format like the primary constructor variables and doesn't let me initialise a value that can then be called like the others.
Problem line: (it's the 'age =' bit)
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
full syntax below:
fun main() {
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
var phoneOne = MobilePhone("Samsung", "Galaxy", "S20",)
println("What is your hobby?: ")
phoneOne.hobby = readLine().toString()
phoneOne.stateHobby()
phoneTwo.hobby = "Plumbing"
phoneTwo.stateHobby()
phoneTwo.age = 32
println("PhoneTwo is $phoneTwo.age years old")
}
class MobilePhone(osName: String, brand: String, model: String) {
// member variables - Properties - variables within a class
var age : Int? = null
var hobby : String = "Watch Netflix"
// Initializer block
init {
println("A new mobile phone was created called $osName which is " +
"brand $brand and it's model is $model")
}
// member secondary constructor
constructor(osName: String, brand: String, model: String, age: Int):
this(osName,brand,model){
this.age = age
}
// Member function - functions within a class
fun stateHobby() {
println("Your hobby is $hobby")
}
This is about the syntax of calling a method/constructor in Kotlin, not about secondary constructors as such (which are called in exactly the same way as others).
First, let's review the syntax for calling a method (or constructor). You can just list the arguments alone (just as you do in Java, C, or many other languages), e.g.:
MobilePhone("Apple", "iphone", "X", 5)
However, Kotlin also allows you to specify the names of the parameters they're being passed to, e.g.:
MobilePhone(osName = "Apple", brand = "iphone", model = "X", age = 5)
That's more long-winded, but you may find it easier to read and safer (especially if there are multiple parameters with the same type). It also lets you put the arguments in any order, e.g.:
MobilePhone(model = "X", osName = "Apple", age = 5, brand = "iphone")
You can even mix and match the forms, as long as the unnamed arguments come first, e.g.:
MobilePhone("Apple", "iphone", age = 5, model = "X")
(This feature is only mildly useful on its own, but is very handy for a related feature: the ability to specify default values for some or all of the parameters. See that link for more.)
Hopefully this illustrates why the problem line doesn't make sense:
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
That looks like you want to call the secondary constructor, passing the values "Apple", "iphone", and "X" to the first three parameters, and then naming another parameter but without passing it a value. This is of course a syntax error.
If you have a value to pass for the age, then just pass it, either with the parameter name:
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = 5)
or without:
var phoneTwo = MobilePhone("Apple", "iphone", "X", 5)
Or if you don't have a value, then simply call the primary constructor instead:
var phoneTwo = MobilePhone("Apple", "iphone", "X")
Incidentally, this means that your class doesn't actually need a secondary constructor at all. You could simply include the optional parameter in the primary constructor, with a default value:
class MobilePhone(osName: String, brand: String, model: String, var age: Int? = null) {
Then callers can either specify the age param, or omit it (and get the null default value).
In fact, features such as multiple constructors, method overloading, and builder classes tend to be used less in Kotlin than in some other languages, because default parameters cover their main use cases.
I'm not sure what you're trying to do exactly, but hopefully this covers it! This:
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
is trying to call your secondary constructor, and you're using a named argument for one of the parameters (age) but you're not actually passing a value for it. If you do, it'll compile
MobilePhone("Apple", "iphone", "X", age = 3)
You don't actually need to name the argument there - if you just pass an Int as the 4th parameter, it'll match your secondary constructor's signature (number of parameters, correct types for each, in the same order), so the compiler will know that's what you're calling. If you omit it, it'll match the primary constructor. You can still keep the name there for readability, if you like.
But you can actually duplicate the functionality you have there with a default parameter, which is where you supply a value to use if the call doesn't specify one:
class MobilePhone(osName: String, brand: String, model: String, val age: Int? = null) {
// member variables - Properties - variables within a class
var hobby : String = "Watch Netflix"
// Initializer block
init {
println("A new mobile phone was created called $osName which is " +
"brand $brand and it's model is $model")
}
So now, age is a parameter on the primary constructor - if you don't supply it (just calling with the first 3 items, which are required because they don't have defaults) then it defaults to null.
By making that parameter a val (or a var if you like) it becomes a class property you can reference later, instead of only being accessible during construction. So you can remove the var age property inside the class, because this is basically the same thing (and they'll clash anyway)
And now that you have a primary constructor you can call with or without the age parameter, there's no need for the secondary one anymore! This is where named parameters really come in useful - if you had defaults for each of those params, you could just supply the specific ones you're interested in, by using their names
oh also, "PhoneTwo is $phoneTwo.age years old" won't work - if you're just referencing an object, you can do $phoneTwo, but anything more complicated (like accessing one of its properties, or any method calls or more complex expressions) have to be wrapped in ${}
println("PhoneTwo is ${phoneTwo.age} years old")
println("PhoneTwo is ${phoneTwo.age * 365} days old")

How do I pull entries from an ArrayList at random in Kotlin?

This is my first Kotlin project. I am learning as I go and I have reached a roadblock.
I have an ArrayList of questions that I want to pull into that app in a random order. I've tried assigning the .random to the point where the question is assigned (right now it is set to CurrentPosition-1) but that only randomized the question and didn't pull the correct answers along with the questions.
How do I either bundle the answers to the question or is there a better way to get the questions to shuffle in order? I plan on having 50+ questions but only 10 will show each time the test is taken. I don't want the same 10 questions showing each time the user opens the test.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quiz_questions)
mQuestionsList=Constants.getQuestions()
setQuestion()
}
private fun setQuestion(){
val question = mQuestionsList!![mCurrentPosition-1]
defaultOptionsView()
if(mCurrentPosition == mQuestionsList!!.size){
submitBtn.text = "Finish"
}else{
submitBtn.text = "Submit"
}
progressBar.progress = mCurrentPosition
tv_progress.text = "$mCurrentPosition" + "/" + progressBar.max
tv_question.text = question!!.question
test_image.setImageResource(question.image)
tvOptionOne.text = question.optionOne
tvOptionTwo.text = question.optionTwo
tvOptionThree.text = question.optionThree
tvOptionFour.text = question.optionFour
}
private fun defaultOptionsView(){
val options = ArrayList<TextView>()
options.add(0, tvOptionOne)
options.add(1, tvOptionTwo)
options.add(2, tvOptionThree)
options.add(3, tvOptionFour)
Here is my Array
object Constants{
const val TOTAL_QUESTIONS: String = "total_questions"
const val CORRECT_ANSWERS: String = "correct_answers"
fun getQuestions(): ArrayList<Question>{
val questionsList = ArrayList<Question>()
val q1 = Question(
R.drawable.questionmark,
1,
"Who is Regional Manager of\n Dunder Mifflin Scranton?",
"Michael",
"Jim",
"Pam",
"Dwight",
1,
)
I appreciate any help at all. Thank you in advance.
list.shuffled().take(10) And make your mQuestionsList property type List instead of ArrayList since you don’t need to modify it after retrieval. You should also probably make it lateinit or initialize it at its declaration site so you won’t have to make the type nullable and have to resort to !!, which is generally a code smell. So I would declare it as var mQuestionsList: List<Question> = emptyList() and whenever you want new values do mQuestionsList = Constants.getQuestions().shuffled().take(10).

how to set multiple kotlin variables in one line

I want to fill two variables in the same line, but I don't know the best way to do it at kotlin
var a:String? = null
var b:String? = null
a, b = "Text"
Not possible in Kotlin (unless you are ready to resort to some contrived constructs with repetition as described in other answers and comments). You cannot even write
a = b = "Text"
because weirdly enough, assignments are not expressions in Kotlin (as opposed to almost everything else like if, return, throw, swicth, etc., which are expressions in Kotlin, but not in Java, for example).
So, if you want to assign exactly the same value without repetition (of the assigned value), you'll have to write
a = "Text"
b = a
Note, that there is also an also function (pun intended), so technically you can write the following if you really want to stay on one line
a = "Text".also { b = it }
but I doubt it is really worth it.
var a: String? = null; var b: String? = null
or
var (a: String?, b: String?) = null to null
But please don't ever do so
Simply create an inline array, iterate through and assign values.
arrayListOf(a, b, c, d).forEach { it = "Text" }

How to convert Object(with value) into Map

I have a object that I want to print it into string [key1=value1&key2=value2...etc] without the null value key value pair and comma into &.
So first of all i think of putting it into a map but it won't work and I don know how it work either.
val wxPayOrderObj = WxPayOrder(appid = "wx0b6dcsad20b379f1", mch_id =
"1508334851", nonce_str = UUID.randomUUID().toString(),sign = null,
body = "QQTopUp", out_trade_no = "20150806125346", total_fee = req.total_fee,
spbill_create_ip = "123.12.12.123",
trade_type = "JSAPI", openid = "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o")
so the output will be
appid=wx0b6dc78d20b379f1&mch_id=150788851&nonce_str=UUID.randomUUID().toString()&
body=QQTopUp&out_trade_no=20150806125346&total_fee=req.total_fee&
spbill_create_ip=123.12.12.123&trade_type=JSAPI&openid=oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
anyone please help me, thanks in advances.
I don't really get your question, but you want to convert object to string (to a format that you want)?
Override the object's toString() to return "[key1=value1&key2=value2...etc]"
example
override fun toString(){
// make sure you compute the data first
val answer = "[key1=$value1&key2=$value2...etc]"
return answer
}
The $ is used in string templates (That's directly writing the name of a variable, the value will be used later to be concatenated) with other strings)