Can somebody explain this Android-Kotlin code? Please - android

i am new to Android development with Kotlin pogramming language, i am not able to understand this code below,
what i am guessing is that an instance(scanResultAdapter) is created from ScanResultAdapter class, this class has the code for recyclerView adapter.
This code is in MainActivity.kt file in punchThrough's article about BLE -
private val scanResultAdapter: ScanResultAdapter by lazy {
ScanResultAdapter(scanResults) { result ->
// User tapped on a scan result
if (isScanning) {
stopBleScan()
}
with(result.device) {
Log.w("ScanResultAdapter", "Connecting to $address")
connectGatt(context, false, gattCallback)
}
}
}

Which point you don't understand?
Regards your guess(the logic of code), that's right, I think.
It seems that you are not familiar with Kotlin, you can check them one by one. For an instance, I don't know this style code:
ScanResultAdapter(scanResults) { result ->
....
}
{ result -> .. }, I need to know that's the Lambdas Expressions
Here's a reference
Maybe I don't understand the with of Kotlin, refer to this document and so on.

You are right. (scanResults) is the first argument of constructor. Second is callback of click listener in curly brackets. When user tap on a device in the list this code in braces {} will be executed. Kotlin can take out of parentheses () arguments if it is functions.

Related

type mismatch when trying to read List from internal Storage

I am new to Kotlin so please excuse this question, as it is probably pretty stupid...
So I followed the tutorial by Philipp Lackner to create a Todo-List as an android app if any of you know that. Now I tried to add a read and write functionality to this app by saving into a simple .txt-file for now.
For that I tried to follow this tutorial as much as possible, but now I am running into Problems when writing code to load the Todo-Items from a file.
I wrote this function to load Todo-Items from the .txt-file:
private suspend fun loadTodoItemsFromInternalStorage(): List<Todo> {
return withContext(Dispatchers.IO) {
val todoItemList: MutableList<Todo> = mutableListOf<Todo>()
var isEven = true
val files = filesDir.listFiles()
files?.filter { it.canRead() && it.isFile && it.name.endsWith(".txt") }?.map {
val lines = it.bufferedReader().readLines()
for (i in lines.indices) {
isEven = if(isEven) {
todoItemList.add(Todo(lines[i], lines[i+1].toBoolean()))
!isEven
} else {
!isEven
}
}
todoItemList
} ?: mutableListOf<Todo>()
}
}
Why do I get that type mismatch? I even initialize the list I want to return as a MutableList of type Todo, but I guess the type inference of Kotlin turns it into a MutableList of type Any?
So how do I fix this? And if you want to you could tell me better ways to do what I did (e.g. saving Todo-items (which consist of title and a boolean whether they are checked or not) to a file)
My plan to keep this as simple as possible as this is my first Kotlin project was to just use 2 lines for a Todo-item, where the first line is the title and the second line is the status whether it has been checked or not. I hope that makes my code easier to understand.
Thank you so much for your help in advance! I appreciate it a lot, as I have been struggling with coding in the past and really want to improve my coding skills.
If you cast your return statement, the code should work. Taking your code as a basis:
private suspend fun loadTodoItemsFromInternalStorage(): List<Todo> {
return withContext(Dispatchers.IO) {
...
} ?: mutableListOf<Todo>()
} as MutableList<Todo>
}
Some additional suggestions:
when dealing with file handling in general: error handling, check for correct format, empty entries, ...
the check for isEven/isOdd is obsolete and the code can be shortened to great extent when you use the step-option within the for-loop
for (i in lines.indices step 2) {
todoItemList.add(Todo(lines[i], lines[i+1].toBoolean()))
}

Kotlin inline function for checking if user is autheticated or not?

I want to execute a block of code after checking if user is authenticated or not. Something like this:
inline fun <T : Any, R> T?.isUserAuthenticated(callback: (T) -> R) {
FirebaseAuth.getInstance().currentUser?.let {
//Function call
} ?: kotlin.run {
FirebaseAuth.getInstance().signInAnonymously().addOnSuccessListener {
//Function call
}
}
This approach isn't working, but is there any alternative to this?
Inline functions in Kotlin should be used over regular functions when:
You desperately need to allocate memory more efficiently.
When a function accepts another function or lambda as an argument.
You need to prevent object creation and have better control flow.
Otherwise, inlining may cause the generated code to grow. Most likely there are also other situations when it is worth using inline functions but I only added a few (important) of them.
When it comes to checking if a user is authenticated or not, I would rather create a regular function that looks like this:
fun getAuthState() = auth.currentUser != null
And use it:
val isAuthenticated = getAuthState()
if(!isAuthenticated) {
auth.signInAnonymously().addOnCompleteListener(/*...*/)
}
Or if using Kotlin Coroutine:
if(!isAuthenticated) {
auth.signInAnonymously().await()
}
So it's one approach or the other.
I would add this function in a repository class so it can be used all across the entire project.
If you're interested in seeing some code, I recommend you check the following resource:
How to handle Firebase Authentication in clean architecture using Jetpack Compose?
And here is the corresponding repo.

How to get the caller from an event handler as an object in Kotlin

I am really new to Kotlin and since I'm not used with the terminology I haven't found anywhere how can I get an object from an event caller.
For example, instead of writing "addToStack(b1)" I want to write something like addToStack(general term to get the same result):
b1.setOnClickListener{
addToStack(b1)
}
Is there a way to do that?
Either write
b1.setOnClickListener {
addToStack(it)
}
or
b1.setOnClickListener { iAmB1ButWithACustomName ->
addToStack(iAmB1ButWithACustomName)
}

kotlin call function with android view

We are trying to understand calling a function in Kotlin
The function looks like this
fun onSIMPLE(view: View){
val snack = Snackbar.make(view,"This is a simple Snackbar", Snackbar.LENGTH_LONG)
snack.show()
}
And the call is made this way
btnSB2.setOnClickListener {onSIMPLE(it)}
What we do not understand is how does one know to use the keyword "it"?
Who ever created the keyword "it" must have never searched the Web
We plugged every reasonable keyword in the ( ) to solve the issue
YES we also looked at the documentation
Is there a better way to construct the function or make the call?
it is the implicit name for a single parameter lambda. You can override as you wish, e.g:
btnSB2.setOnClickListener { view -> onSIMPLE(view)}
setOnClickListener expects a lambda as a parameter, using a Java-like approach, this should look like this:
btnSB2.setOnClickListener({
v:View -> onSIMPLE(it)
})
Also, if the lambda is the last parameter for a given function, it can be specified outside of the parenthesis, which would look like this:
btnSB2.setOnClickListener {
v:View -> onSIMPLE(it)
}
It is common for lambda functions to have a single parameter. For these functions, Kotlin maintains the it keyword. Knowing this, the code becomes:
btnSB2.setOnClickListener {
onSIMPLE(it)
}

Kotlin lambda compiles against java API but not against my own function

Here is a simplified example. This syntax works :
Handler().post({Log.v(TAG, "test")})
However, if I define this function
private fun doWithRunnable(toRun:Runnable) {
// whatever
}
And call it like this
doWithRunnable({Log.v(TAG, "test")})
Then I get the following error:
Required: RunnableFound: () -> Int
Both signatures look quite the same to me... what's the big difference?
In your Java example, you're taking advantage of the Java-interop feature for SAM Conversions. Unfortunately, this does not currently work for Kotlin interfaces, as the designers have deemed it unnecessary (there is some discussion on this see here).
Instead, you'd want to do something like:
fun doWithRunnable(runnable: () -> Any) {
// call it as `runnable()`
}
You could also define a typealias for this if you wanted (which is as close Kotlin comes to SAM syntax):
typealias RunMe = () -> Any
fun doWithRunnable(runnable: RunMe) {
runnable()
}
Note that currently, typealiases have to be declared at the top level, they can't be declared inside a class or method.

Categories

Resources