I've tried hundreds of ways to resolve this reference problem:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val dm = DataManager()
val adapterCourses = ArrayAdapter<CourseInfo>(context: this,
android.R.layout)
but in ArrayAdapter<CourseInfo>(context: this, android.R.layout) I get unresolved reference: context and I have no idea why.
Android Studio version: 3.3.2
Kotlin version: 1.3.21
Could anyone help me?
I had a similar error message because I didn't import the Context.
If you haven't explicitly imported Context, try adding this to your import list near the start of your Activity file:
import android.content.Context
The column in Kotlin is used for some things, but not when passing named arguments. The syntax for passing a named parameter is parameterName = parameterValue.
When you write context = this, while passing a parameter, you are simply referring to the parameter context of the function you are calling, explicitly saying that this has to correspond to that context parameter. This is not very useful in this case unless you want to be very explicit.
The usefulness of using named arguments arise when you are dealing with optional parameters or when you are passing the parameters out of order.
E.g.
// DECLARATION of function abc
fun abc(s: String = "", i: Int = 0)
// USAGE of function abc passing only an Int
abc(i = 314)
The function abc has two parameters and they have a default value. In this case, you can avoid passing any parameter if you are fine with the defaults.
But if you only want to pass i, you can do it by specifying its name, as done in the example.
Similarly, you can choose to pass parameters out of order, in that case, you'll do:
abc(i = 314, s = "something")
Related
I made a functions.kt file for global variables and I made this:
import android.app.Application
class variable : Application() {
var currentLesson: String? = null
}
After that, I used it in main.kt like so:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button: Button = findViewById(R.id.button1)
var functions = variable()
var currentLesson = functions.currentLesson
button.onClickListener {
currentLesson = "text"
}
}
override fun onBackPressed() {
someview: View =
findViewById(R.id.view1)
var functions = variable()
var currentLesson = functions.currentLesson
if (currentLesson == "text") {
someview.visibility = View.VISIBLE
}
}
}
In onBackPressed() it's always null. But not in onCreate(). Where is the problem?
Every time you call variable() you are creating a new instance of the class variable so it has its own memory and state that it's holding.
Incidentally, you should not be subclassing Application to create this class, since your simple data holder is not an Application!
If you want a class to hold some shared state for the whole app, that's commonly called a singleton (a class with only one instance), and you can easily create one in Kotlin using an object instead of class.
object Variable {
var currentLesson: String? = null
}
Then when you use it in your Activity, you can call it directly with Variable.currentLesson without having to create an instance of the class.
Alternatively, you can put the variable outside of any class, and it will be a global property that can be accessed from anywhere. In my opinion, that's kind of an ugly solution because it pollutes the namespace.
Note, you should be careful about what you store in global variables like this. It is not good practice to put large, memory-hungry objects in a global variable that will cause that memory to be used for longer than necessary.
Also, it is convention to make class names always start with a capital letter. It will make your code much easier to read and understand, especially in languages like Kotlin which omit the new keyword used for constructor calls.
I am kind of new to Android. I can't figure this out. I want to create an object that is accessible from two different functions. Here is the object:
class Person(var firstName: String="", var lastName: String="", var order: List<Orders> )
class Order(var orderId: String="", var orderTitle: String="")
Then in an activity:
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var order: Order()
var person: Person(order) //I am sure I am not doing this right
}
fun Function1(){
person.order[1].orderTitle = "New Order" //to update order title
}
fun Function2(){
// to read new order title
var newOrderTitle = person.order[1].orderTitle
}
}
You created your Person instance as a local variable inside the onCreate() function, so it is only accessible inside the onCreate() function. To make it accessible from your other functions, it needs to be a property member of the class (defined outside any functions). You also need to use the = symbol to set the initial value. The : symbol is for declaring what type the property or variable is, and is optional in most cases.
By the way, in Kotlin, the convention is to always start function names with a lower-case letter, so it is easy to distinguish them from constructors. (This differs from languages like C#, where the new keyword makes constructor calls obvious.)
class MainActivity : AppCompatActivity(){
var order = Order()
var person = Person(order)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun function1(){
person.order[1].orderTitle = "New Order" //to update order title
}
fun function2(){
// to read new order title
var newOrderTitle = person.order[1].orderTitle
}
}
As well as what #TenFour04 says about making the variables visible to the functions, there's a couple of problems with how you're creating your Person object.
First, you're using default values for everything so you don't need to pass in a value for every parameter, right? That's how you can call Order() without providing any other data. But if you are passing in data, like with your Person(order) call, you need to tell it which parameter you're passing by using a named argument:
Person(order = order)
using the same name for the variable you're passing in and the name of the argument maybe makes it look more confusing, but you're specifically saying "the argument called order, here's a value for it".
You can pass in arguments without names, but you have to provide them in the order they're declared - so the 1st argument (a String), or the 1st and 2nd, or the 1st, 2nd and 3rd. Since you want to jump straight to the 3rd argument, you need to explicitly name it.
Second issue is your 3rd argument's type isn't Order, it's a List of orders. You can't just pass in one - so you need to wrap it in a list:
Person(order = listOf(order))
that's all you need to do!
The third problem is you've actually written the type as List<Orders> (sorry about the formatting). The type is Order, so we say List<Order> because it's a list holding objects of the Order type. You can use plurals in your variable names though (like val listOfOrders: List<Order>)
i don't know why but i get this error:
e: C:\Users\User\AndroidStudioProjects\StorageManagementTheThird\app\src\main\java\com\example\storagemanagementthethird\AddItemActivity.kt: (15, 35): Type inference failed: Not enough information to infer parameter T in fun <T : View!> findViewById(p0: Int): T!
in this code:
class AddItemActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.add_item)
val addItemSubmitButton = findViewById(R.id.addItemSubmitButton)
addItemSubmitButton.setOnClickListener {
val editTextItemName: EditText = findViewById(R.id.editTextItemName)
//alles wat we aanpassen in storage en opslaan
val database = getSharedPreferences("database", Context.MODE_PRIVATE)
database.edit().apply {
putString("savedItemName", editTextItemName.text.toString())
}.apply()
}
}
}
please help me if you can :)
You should change this line
val addItemSubmitButton = findViewById(R.id.addItemSubmitButton)
like below
val addItemSubmitButton = findViewById<View>(R.id.addItemSubmitButton)
findViewById takes a type, so it can return the correct type of view - in this case you should probably use findViewById<Button> since that's what the view it meant to be, but it doesn't really matter since you can set a click listener on any type of View
If you actually specify the type on the val declaration, like val addItemSubmitButton: Button then the compiler can infer the type for the findViewById call, and you don't need the type in the diamond brackets (it'll be greyed out and you'll get a suggestion to delete it). That's why your editTextItemName lookup is fine - you're specifying the type for that one
I am trying to write a function in kotlin but I am not able reassign value to function parameters ,its saying val cannot be reassigned .
class WebView{
var homepage = "https://example.com"
fun webViewLoad(url: String, preferredOrientation: String) {
if (url.equals("homepage")){
url = homepage
}
}
}
when I am trying to assign a value to url = homepage .it is giving me error val cannot be reassigned , I am new to kotlin ,I do not understand what is the issue , little help will be appreciated.
Function parameters works like val variables that couldn't be reassigned. Here you need to add variable with conditional initialization:
fun webViewLoad(url: String, preferredOrientation: String) {
val urlValue = if (url.equals("homepage")){
homepage
} else {
url
}
... //use here "urlValue" variable
}
By the way, in kotlin you don't need to use equals function to compare string: common operator == will be automatically replaced with equals in byte code.
Kotlin parameters are immutable since Kotlin M5.1
(Reference)
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime). Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing if a function declarations (namely, it creates a property). Also, we all know that mutating parameters is no good style, so writing “val” or “var” infront of a parameter in a function, catch block of for-loop is no longer allowed.
It is giving you error "val cannot be reassigned" because Kotlin function parameters are immutable i.e "val" by default. You don't need to mention the "val" keyword for it.
Quick Solution would be:
class WebView{
var homepage = "https://example.com"
fun webViewLoad(url: String, preferredOrientation: String) {
val finalUrl = if (url.equals("homepage")) homepage else url
}
}
Kotlin function parameters are final. There is no val or final keyword because that's the default (and can't be changed). Have a look at this.
By default parameters passed in the function are final what you can do is to add var. Hope it helps.
fun webViewLoad(var url: String, preferredOrientation: String) {
if (url.equals("homepage")){
url = homepage
}
}
Given an interface method like this (Android Retrofit), how do I read the URL path specified in the annotation argument from Kotlin code at runtime?
ApiDefinition interface:
#GET("/api/somepath/objects/")
fun getObjects(...)
Read the annotation value:
val method = ApiDefinition::getObjects.javaMethod
val verb = method!!.annotations[0].annotationClass.simpleName ?: ""
// verb contains "GET" as expected
// But how to get the path specified in the annotation?
val path = method!!.annotations[0].????????
UPDATE 1
Thanks for answers. I'm still struggling as I can't see what type to use to do the following:
val apiMethod = ApiDefinition::getObjects
.... then to pass that function reference into a method like this (it's reused)
private fun getHttpPathFromAnnotation(method: Method?) : String {
val a = method!!.annotations[0].message
}
IntelliJ IDE is suggesting I use KFunction5<> as a function parameter type (it doesn't exist as far as I can see) and seems to be requiring I specify all the parameter types for the method too, which makes a generic call to get the annotation attribute impossible. Isn't there a Kotlin equivalent of "Method"?, a type that will accept any method? I tried KFunction, without success.
UPDATE 2
Thanks for clarifying things. I've got to this point:
ApiDefinition (Retrofit interface)
#GET(API_ENDPOINT_LOCATIONS)
fun getLocations(#Header(API_HEADER_TIMESTAMP) timestamp: String,
#Header(API_HEADER_SIGNATURE) encryptedSignature: String,
#Header(API_HEADER_TOKEN) token: String,
#Header(API_HEADER_USERNAME) username: String
): Call<List<Location>>
Method to retrieve annotation argument:
private fun <T> getHttpPathFromAnnotation(method: KFunction<T>) : String {
return method.annotations.filterIsInstance<GET>().get(0).value
}
Call to get the path argument for a specific method:
val path = getHttpPathFromAnnotation<ApiDefinition>(ApiDefinition::getLocations as KFunction<ApiDefinition>)
The implicit cast seems to be necessary or the type parameter demands I provide a KFunction5 type.
This code works, but it has the GET annotation hard-coded, is there a way to make it more generic? I suspect I might need to look for GET, POST and PUT and return the first match.
Use the Kotlin KFunction directly instead of javaMethod (you're using Kotlin anyway!), and findAnnotation for concise, idiomatic code.
This will also work if the annotation happens to not be the first, where annotations[0] may break.
val method = ApiDefinition::getObjects
val annotation = method.findAnnotation<GET>() // Will be null if it doesn't exist
val path = annotation?.path
Basically all findAnnotation does is return
annotations.filterIsInstance<T>().firstOrNull()