Kotlin function signature:
fun functionName(varName: varType): returnType { return varName } Example: fun isLegal(age: Int): Boolean { return if(age >= 18) } // or fun isLegal(age: Int): Boolean = age >= 18 // multiple parameters fun applicant(age: Int, name: String) { ... } // function with no return /** fun displayTotal(num1: Int, num2: Int): Unit {} -- using (: Unit) can also delineate the function does not return **/ fun displayTotal(num1: Int, num2: Int) { val total = num1 + num2 println(total) } // function with return fun larger(firstNum: Int, secondNum: Int): Int { val largerNum = if(firstNum > secondNum) firstNum else secondNum return largerNum } // above larger() function can be further simplified: fun larger(firstNum: Int, secondNum: Int): Int = if(firstNum>secondNum) firstNum else secondNum // you can remove return type of function and allow compiler to infer it from your 'if' statement fun larger(firstNum: Int, secondNum: Int) = if(firstNum>secondNum) firstNum else secondNum Calling the function: val legal = isLegal(21) // True val legal isLegal(10) // False Default function parameter values: fun displayMsg(message: String, name: String = "visitor") { println("Howdy $name, $message") } // function calls displayMsg("nice to meet you!", "Sarah") // Output: Howdy Sarah, nice to meet you displayMsg("pleasure to be of acquaintance") // Output: Howdy visitor, pleasure to be of acquaintance Variable number of function arguments // Allows non-fixed number of arguments of declared type (argType) fun funName(vararg argName: argType): returnType { } main() function
public class MainClass { public static void main(String[] args) { System.out.println("Hello world"); } } Kotlin: fun main(args: Array<String>) { println("Hello World") } Static functions class NumberPicker { // 1 companion object allowed per class companion object { // declare function inside a 'companion' object block to delineate 'static' fun spinWheel () { } } } /** call spinWheel(). Unlike Java, no need to call function using a class instance (e.g. NumberPicker c = new NumberPicker(); c.spinWheel(); **/ NumberPicker.spinWheel() Static factory function private class SecretClass private constructor() { companion object() : SecretClass { fun create() : SecretClass { return SecretClass() } } } // instantiate a new SecretClass instance val sc = SecretClass.create() kotlin.collections package - site for reference.
- Allows declarations of immutable or mutable collections List<Double> // immutable List of Double objects MutableList<Double> // mutable List of Double objects Arrays // array type inferred val numArray = arrayOf(1, 2, 3, 4, 5, 6, 7) // array type specified val intArray = intArrayOf(1, 3, 5, 7, 9) joinToString() println(numArray.joinToString() ) // show contents of 'numArray' (1, 2, 3 .. etc) /** Adding symbols/chars before and after the array contents In below example, parenthesis enclosing array contents (1, 2, 3, 4..) **/ println(numArray.joinToString(prefix = "(", postfix = ")")) // specifying separator between array contents other than default commas ',' println(numArray.joinToString(prefix = "(", postfix = ")", separator = "*")) // Output: (1*2*3*4... etc) Lists, Sets, Maps // immutable list val nameList = ListOf("Jen:", "Joe", "Jim") // mutable list val mutableNameList = mutableListOf("Jack", "James", "Joey") // Set: unique contents only, so the set would contain 2 and 4 only val numSet = setOf(2, 2, 4, 4) // mutable set val mutableNumSet = mutableSetOf(2, 2, 4, 4) // immutable map val alphabet = mapOf(1 to "a", 2 to "b", 3 to "c") println(map) // Output: {1=a, 2=b, 3=c} // mutable map val alphabet = mutableMapOf(1 to "a", 2 to "b", 3 to "c", 4 to "d") println(map) // Output: {1=a, 2=b, 3=c, 4=d} if statements:
val num = 21 if (num < 21) { println("Underage drinker") } else { println("Adult") } // Output: Adult Assigning variable with outcome of 'if' statement: // 'age' will be assigned the string after the println() val age = if(num < 21) { printlln("Underage drinker") "Do not allow drinking" // if 'num' is under 21, 'age' assigned "Do not allow drinking" } else { println("Legal drinker") // 'num' is over 21, 'age' assigned "Allow drinking" "Allow drinking" } Using 'if' statement as an expression // corresponding else clause is mandatory when using 'if' as an expression println(if (a > b) "a is greater than b" else "a is less than b") when statements:
val cost = 100 when(cost) { 0 -> println("Free admission") 50 -> println("Half-price admission") 51..99 -> println("Over 50% off admission") else -> println("Full-price admission") // default } // Output: Full-price admission Assigning variable with outcome of 'when' statement: // 'admission' will be assigned the appropriate string based on corresponding 'when' condition val admission = when(cost) { 0 --> "Free admission" 50 --> "Half-price admission" 51..99 --> "Over 50% off admission" else ---> "Full-price admission" } while & do-while loops: // while loops in Kotlin have similar syntax to Java val num = 0 while(i <10) { println("$num ") num++ } do { println(num) num++ } while(num < 20) for loops: for(i in 1..20) { print("$i ") } // or, the above simplified: // Output: Integer range of 1-20 (e.g. 1 2 3 4 5...etc, includes 100) for(i in 1..100) print("$i ") // Output: same as above, but excludes end number 100) for(i in 1 until 100) print("$i ") for(chars in "Kotlin language") { print("$chars ") } // Output: Each character of string w/ space between each character (e.g. K o t l i n l a n g .. etc) Using downTo operator in 'for' condition, reverses range of output for(i in 100 downTo 1) { print("$i ") } // Output: 100, counting down by 1 (e.g. 100 99 98 97 .. etc) Using downTo operator + step for(i in 100 downTo 1 step 5) { print("$i ") } // Output: 100, counting down by 5-step increments (e.g. 100 95 90 85 .. etc) Looping through an array for(item in numArray) { println("$item is an item in numArray") } Looping through an array using its index for((index, item) in numArray.withIndex()) { println("numArray[ $index ] has the element $item) } Looping through a string to print each of its characters val language = "Kotlin" for(c in language) { print(c) } Data types
Integer types
Some points regarding variables and data types in Kotlin:
Kotlin variable declaration
greeting = "Hi again" // not allowed, 'greeting' immutable due to 'val' declaration
greeting = "Hello World, v2" // allowed, 'var' declaration allows mutability var age = 21 // mutable variable (value and reference to object can change) var age: Int = 21 // no semi-colon required at end of declaration statement val name = "John" // 'val' for immutable variables (reference to object unchangable ) val name: String = "John" // equivalent to declaration above val isHuman: Boolean = true Kotlin and immutability or null safety val str: String = null // not allowed val str: String? = null // use '?' after the data type when wanting to assign 'null' val i: Int? = null - Kotlin will warn at compile time when a variable is null Unsafe and safe operators for null in Kotlin // 'str' is null str!!.length // using unsafe operator '!!', throws null pointer exception str?.length /** safe operator that returns null if 'str' is null, the value of 'str.length' if 'str' is not null **/ val length = str?.length ?: -1 /** ?: - Elvis operator. If 'str' is null, assign -1 to 'length', otherwise, length of 'str' assigned value of its 'length' **/ Recently, while working on a personal app project, I became interested in custom styling for the AlertDialog boxes. Overall, I wanted the app to have a unified theme/feel and didn't want to exclude even the small detail of dialog box appearances. Perhaps I had never noticed before, but the ordering of the confirm and cancel buttons/options on the dialog boxes are a little bit odd. Researching the issue, this was apparently a complaint going back to 2012. For those wanting a little more detail, it's basically the ordering of the confirm/cancel buttons that are represented visually and programmatically as: As indicated in the Issue Tracker link, this seems to be an intentional change for Android versions 4.0+. To be fair, I have noticed this similar ordering in operating system alerts (Linux Ubuntu, perhaps) as well, so I suppose it isn't too odd. After taking a hiatus from Android development in Android Studio, I returned to my projects to find the following gradle error: Error:failed to find target with hash string 'Google Inc.:Google APIs:25'. The hash string may vary with each project based on the API it was set to in the compileSdkVersion in your gradle file. Per this StackOverflow post on the matter, the compileSdkVersion also resembled the format of the original poster's (see image below) and shortening to the simple version number (25 at the time of this writing) seemed to fix the issue. So my Android Studio recently updated to build tools version 23.0.2 while working on some Material design updates for my apps. Testing primarily on versions 22+, I hadn't noticed any issues when attempting to compile. However, once testing down to 14 (lowest version currently supported by the apps), I was encountering the following error:
Error inflating class android.support.v7.widget.Toolbar Caused by: android.content.res.Resources$NotFoundException: File res/drawable-v19/abc_ic_ab_back_material.xml After reading this article, AppCompat v23.2 — Age of the vectors, the reasoning behind the error as well as the respective fix can be found. The flag to be enabled in gradle is listed for versions 2.0+ and 1.5 or below. Mistakenly thinking that I was on version 2.0+, the first flag did not work and resulted in the vectorDrawables being non-resolvable. After some research, it was discovered that I was most likely on the 1.5 version or below. However, that flag triggered errors too, particularly for the generatedDensities property as described in the Stack Overflow problem. A final check of the top-level gradle file finally revealed the problem -- it was still referencing 1.2.3! Build system versions are listed at this link - New Build Systems - Android Tools Project Site. Setting the dependencies in the top-level build.gradle, recompile, and voila. Encountered an issue with the back button rendering my Fragment container meant to hold two fragments for a FragmentStatePagerAdapter blank when returning.
In the onCreateView() of the container Fragment where the adapter is being set, rather than previously calling getSupportFragmentManager() in this app that will be targeting down to SDK 14, changing this to getChildFragmentManager() fixed the issue. Now, when returning from a back button press, everything loads fine. Was unaware of Resources.getDrawable(int) deprecation after SDK 22 until updating and getting the dreaded cross-line. For projects targeting lower APIs, ContextCompact.getDrawable(Context, int) of the support library was most appropriate and for other uses, the alternatives found in the Google+ post. More info regarding this:
-- Resources -- ContextCompat -- Android getResources().getDrawable() deprecated API 22 When generating a signed APK for an app using ProGuard with Play Services, I encountered this Issue 3001 preventing the APK from being generated due to errors being thrown up. The two possible workarounds seem to be: A. Add statements to proguard-project.txt -keep class com.google.android.gms.** { *; } -dontwarn com.google.android.gms.** or B. Add missing library back in: android { useLibrary 'org.apache.http.legacy' } Chose option A to avoid enlarging the APK size. Seems to be an issue with SDK 23 and 24 apparently, as it was updated yesterday. Awaiting fix. |
AuthorExploring Android and mobile web design, security, and development. Archives
March 2021
Categories |