lateinit var sharedPreferences : SharedPreferences
var number = 0
var runnable : Runnable = Runnable{ }
var handler : Handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sharedPreferences = this.getSharedPreferences("com.mycompany.runnables", MODE_PRIVATE)
val recordFromSP = sharedPreferences.getInt("record",-1)
textView2.text = "Last Time Record: $recordFromSP"
}
fun start(view:View){
number = 0
runnable = object : Runnable{
override fun run() {
number = number 1
textView.text = "Time: $number"
button3.setEnabled(false)
button4.setEnabled(true)
handler.postDelayed(this,1000)
var record = number
}
}
handler.post(runnable)
}
fun stop(view:View){
handler.removeCallbacks(runnable)
number = 0
textView.text = "Time: 0"
Toast.makeText(this,"Stopped",Toast.LENGTH_LONG).show()
button4.setEnabled(false)
button3.setEnabled(true)
***sharedPreferences.edit().putInt("record",record)***
}
How can I get the last value from the timer(from runnable in start() function) I can't reach the record value from anywhere outside runnable function of course. So it gives an error in "sharedPreferences.edit().putInt("record",record)" How can I take the value?
CodePudding user response:
You can't use it in such a way since the var record
is a local variable of another method inside another anonymous class.
So you need to declare the var record
as a variable of your main Activity class (where you already have var number
and others).
CodePudding user response:
you need something ina scope thats accessible from both start
and stop
function
i would suggest to declare record
in the encloding class/file
maybe like a private plateinit var
then yo can check if it is initialized (aka it ran at least once) before accessing it
or you can make it a plain var
initialized to a default value if you don't care about that
private lateinit var record: Int
fun start() {
number = 0
runnable = object : Runnable{
override fun run() {
number = number 1
textView.text = "Time: $number"
button3.setEnabled(false)
button4.setEnabled(true)
handler.postDelayed(this,1000)
record = number // here it is assigned
}
}
handler.post(runnable)
}
fun stop(view:View){
handler.removeCallbacks(runnable)
number = 0
textView.text = "Time: 0"
Toast.makeText(this,"Stopped",Toast.LENGTH_LONG).show()
button4.setEnabled(false)
button3.setEnabled(true)
// TODO: use if(this::record.isInitialized) to prevent exceptions
sharedPreferences.edit().putInt("record",record)
}
CodePudding user response:
The simple solution here is to just store number
(which is what record
is set to) before you clear it:
// can't access 'record' from outside the runnable (or even outside the 'run' function),
// but it's the same value as 'number', which you can read!
var record = number
fun stop(view:View){
// immediately stop any more updates from happening
handler.removeCallbacks(runnable)
// the runnable has been incrementing 'number' (and referring to it as 'record'),
// so we just need to store whatever value that's reached
sharedPreferences.edit().putInt("record", number)
// now we've stored it, we can clean up and reset everything
number = 0
textView.text = "Time: 0"
Toast.makeText(this,"Stopped",Toast.LENGTH_LONG).show()
button4.setEnabled(false)
button3.setEnabled(true)
}
As a more general case, when you're declaring anonymous objects, then any properties you add to them (like a top-level record
property, as opposed to the local variable you were creating in run()
) will only be visible inside the function that created it:
// storing the Runnable where everything can access it
lateinit var myRunnable: Runnable
fun start() {
// creating a Runnable stored at the top level, with an extra property
myRunnable = object : Runnable {
// adding a public property
var record = 0
override fun run() { ... }
}
// you can access 'record' here because the object was declared in this function's
// scope, so the compiler -knows- it has that 'record' property
println(myRunnable.record)
}
fun stop() {
// you can't do this here, because this function only knows 'myRunnable's -declared type-.
// It doesn't know it has a 'record' property, only that it has a 'run()' function
// (since it's a Runnable)
println(myRunnable.record)
}
So you'll have to create an actual class
with that property defined on it, so that everything interacting with that object knows about record
:
abstract class RecordRunnable : Runnable {
abstract var record: Int
}
lateinit var myRunnable: RecordRunnable
fun start() {
// creating a Runnable stored at the top level, with an extra property
myRunnable = object : RecordRunnable() {
// override since it's a property declared on the type
override var record = 0
override fun run() { ... }
}
}
fun stop() {
// now this works because 'record' is a property on the declared type, RecordRunnable
println(myRunnable.record)
}
You could also create a single top-level object
declaration instead of creating a class
(if you want to reuse the same singleton Runnable
instead of creating new instances of it). You can read more about this stuff here!