We are trying to set the value of a global variable declared in the code below
class MyApplication: Application() {
var globalVar = 2
}
Now we have a Main Activity that has a Edit Text named etPerson we would like to enter a value in etPerson and set the entered value equal to globalVar
Why because we want to make a call to a database function in another Activity
Here is the code that makes the call to the DB
var mApp = MyApplication()
var intGlobalVar = mApp.globalVar
println("############################ globalINT = "+intGlobalVar)
var ITEM = db.getItem(intGlobalVar)
println("%%%%%%%%%%%%%%%%%% ITEM "+ITEM?.id+" name "+ITEM?.name)
And for clarity here is the DB function
fun getItem(id: Int): Contact? {
val db = this.writableDatabase
val selectQuery = "SELECT * FROM $TABLE_NAME WHERE $colId = ?"
db.rawQuery(selectQuery, arrayOf(id.toString())).use {
// .use requires API 16
if (it.moveToFirst()) {
val result = Contact(0)
result.id = it.getInt(it.getColumnIndex(colId))
result.name = it.getString(it.getColumnIndex(colName))
return result
}
}
return null
}
So the issue is setting the var globalVar to the value entered in etPerson on the Main Activity
The concept can be accomplished using put and get with intents but that is not our goal here
Our question is how to set the globalVar to the value entered in the Edit Text?
When your app starts one and only one object of the class MyApplication() will be created, so you don't need:
var mApp = MyApplication()
You can access MyApplication() and all its members from everywhere in your app.
Declare a companion object in MyApplication() and put globalVar's declaration inside:
class MyApplication: Application() {
companion object {
var globalVar = 2
}
override fun onCreate() {
super.onCreate()
// initialization code here
}
}
So in your MainActivity class or elsewhere you can use MyApplication.Companion.globalVar to get or set its value.
Or you can import the globalVar variable in any class like:
import yourpackagename.MyApplication.Companion.globalVar
and refer to it simply globalVar
You also need to declare MyApplication in the manifest:
<application
android:name=".MyApplication"
I use this way to send an Intent :
Target activity or class or object (Reciver):
class ReturnActivityIntent private constructor() {
var data: Intent? = null
companion object {
val instance = ReturnActivityIntent()
}
}
In the MainActivity (Sender)
val returnActivityIntent: Notifications.ReturnActivityIntent = Notifications.ReturnActivityIntent.instance
returnActivityIntent.data = Intent(this, MainActivity2::class.java)
so you can change or share variables in this way
Related
I am trying to set the Snacksbar message and action texts with values from strings.xml. If I call .toString() on the values it will obviously be set to some random numbers, as expected. I can't get a reference to context, because it isn't a composable function, so I can't use LocalContext.current meaning I cannot access .getString(). How do I set the value of the message and action properly?
fun onEvent(event: TaskListEvent) {
when (event) {
is TaskListEvent.OnDeleteTask -> {
viewModelScope.launch(Dispatchers.IO) {
deletedTask = event.task
repository.deleteTask(event.task)
sendUiEvent(
UiEvent.ShowSnackbar(
message = "Task successfully deleted!", action = "Undo"
)
)
}
}
It looks like you need an Application class so you can get context when you need it. You have to set the android:name in the application tag in the manifest to the Application class that you use
Something like,
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
val context: Context
get() = this
companion object {
var instance: MyApplication? = null
private set
}
}
the Usage for this class is
MyApplication.instance
MyApplication.instance?.context
class MainAcitvity
fun roomSetup(){
setFavouriteDao = FavouriteDatabase.getDatabase(applicationContext).setFavouriteDao()
repositoryRoom = LorRepository(setFavouriteDao)
viewModelRoom = ViewModelProvider(this,LorViewModelFactory(repositoryRoom!!)).get(LorViewModel::class.java)
}
override fun onMovieClick(position: Int) {
roomSetup()
Toast.makeText(this#MainActivity, "clicked!"+position, Toast.LENGTH_SHORT).show()
var setFavourite = SetFavourite(movieResponse!!.docs[position].Id.toString(),movieResponse!!.docs[position].name.toString())
viewModelRoom.addToFavourites(setFavourite)
}
class ViewModel
fun addToFavourites(setFavourite: SetFavourite){
viewModelScope.launch(Dispatchers.IO){
lorRepository.addToFavourites(setFavourite)
}
}
class LorRepository( favouriteDao: SetFavouriteDao?) {
var favouriteDao : SetFavouriteDao
init {
this.favouriteDao = favouriteDao!!
}
private var lorApi: LORApi.LorCalls? = null
constructor(lorApi2 : LORApi.LorCalls?, favouriteDao: SetFavouriteDao?) : this(favouriteDao){
this.lorApi = lorApi2
}
I have 2 constructors
one to initialize room other for initializing retrofit
I am Also doubtful about the constructor in Repository. Thoose are made for 2 different purposes, one for initializing room database and other for repository. but everytime I create one object of room/retrofit the second constructor , when called, fills it with null values
My questions for you are:
Why do you to initialize retrofit and room's dao in a separate constructor?
What is it that you try to achieve?
In your code you only call to initialize dao constructor, therefore lorApi is null.
For your case you wouldn't want to initialize them separately.
Change your code to this:
class LorRepository(private val lorApi : LORApi.LorCalls, private val favouriteDao: SetFavouriteDao)
In Kotlin, using a scope function such as "with" that allows the this reference inside the block to reference the lambda result, is it possible to reference the outer class member when it has the same name as one of the fields in the result?
eg
data class Person(name: String)
...
class MyClass {
var name = ""
with(personRepository.getPerson(personId)) {
// How do we set the class "name" member - "this.name" or just "name" refers to the scoped object?
name = this.name // ???
}
Obviously using a different variable name is the simple workaround but just wondering if there is a syntax for when the variables have the same name
class MyClass {
var personName = ""
...
with(personRepository.getPerson(personId)) {
personName = this.name
}
the this refers to the object that you pass. In order for you to refer to the context of your class you would need to use labels like below. Do note that this is an anti pattern. With scoping functions you would only want to apply logic on the object that you are passing or that is the receiver object in scoping functions like let and apply
class MyClass {
var name: String = ""
val person = Person("my name")
fun setName() = with(person) {
this#MyClass.name = person.name
}
}
I would suggest using let{} instead of with{}:
data class Person(name: String)
...
class MyClass {
var name = ""
personRepository.getPerson(personId).let {
name = it.name
}
You can use a labeled this to refer to the variable in MyClass. Like this:
with(personRepository.getPerson(personId)) {
this#MyClass.name = name
}
There is integer variable 'a' in Class A, and method
Class A {
var a = 0
fun setA(int: Int) {
a = int
}
}
I used it in Class B by
Class B {
var classA = A()
classA.setA(10)
}
Then I want to set a to 100 in another class, Class C
But If I declare classA as A() and classA.setA(100) in same method of B, this doesn't change value of a referred in class B.
How to globally change the value of a in one place so that it's the same for all other classes?
class A {
companion object {
var a: Int = 0
}
}
perhaps you're looking for a companion object ? this allows global access to the same instance of a
you can now do:
A.a = 5
or in your case :
fun changeValue(int: Int) {
a = int
}
and this value will be the same everywhere
if you're trying to read the value back:
var example = A.a
note how I'm not creating an instance of A anywhere, because using a companion object is the same as using static in java, basically meaning that you can treat this as if an instance already exists
I have a LiveData property for login form state like this
private val _authFormState = MutableLiveData<AuthFormState>(AuthFormState())
val authFormState: LiveData<AuthFormState>
get() =_authFormState
The AuthFormState data class has child data objects for each field
data class AuthFormState (
var email: FieldState = FieldState(),
var password: FieldState = FieldState()
)
and the FieldState class looks like so
data class FieldState(
var error: Int? = null,
var isValid: Boolean = false
)
When user types in some value into a field the respective FieldState object gets updated and assigned to the parent AuthFormState object
fun validateEmail(text: String) {
_authFormState.value!!.email = //validation result
}
The problem is that the authFormState observer is not notified in this case.
Is it possible to trigger the notification programically?
Maybe you can do:
fun validateEmail(text: String) {
val newO = _authFormState.value!!
newO.email = //validation result
_authFormState.setValue(newO)
}
You have to set the value to itself, like this: _authFormState.value = _authFormState.value to trigger the refresh. You could write an extension method to make this cleaner:
fun <T> MutableLiveData<T>.notifyValueModified() {
value = value
}
For such a simple data class, I would recommend immutability to avoid issues like this altogether (replaces all those vars with vals). Replace validateEmail() with something like this:
fun validateEmail(email: String) = //some modified version of email
When validating fields, you can construct a new data object and set it to the live data.
fun validateFields() = _authFormState.value?.let {
_authFormState.value = AuthFormState(
validateEmail(it.email),
validatePassword(it.password)
)
}