Issue
Currently my app has 4 activities and everything is fine as I want it to be until the app comes to the 3rd activity. Instead of going to the next activity i.e, 4th activity. It goes back to the 2nd activity from the 3rd activity.
I also tried adding a button in the main activity which would take me directly to the 4th activity and when I clicked the button, the app just crashed.
In the third activity I have a count down timer and i want the app to go to the next activity after the timer is finished. So in the OnFinish function the code is:
override fun onFinish() {
finish()
val intent = Intent(this@ThirdActivity, FourthActivity::class.java)
startActivity(intent)
}
Edit 1: In the logcat I was redirected to a line of code that caused the error. In the 4th activity, I declared a variable before the onCreate method and when I removed that line, the 4th activity was running fine but I actually want that variable declared.
private val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
and I declared it before the OnCreate method because i was able to call the vibrator.cancel()
in the setOnClickListener of a button and if I declare the variable-- Vibrator in the function I created to vibrate the device then i get an unresolved reference error where i call the vibrator.cancel()
inside the setOnClickListener
The code where I get unresolved reference error after declaring the variable "vibrator" in the vibrate function:
btnFinish.setOnClickListener{
finish()
vibrator.cancel()
}
Edit 2:
I somehow made the app run and everything is running fine.
The vibrate function:
private fun vibrate(context: Context){
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createWaveform(pattern,-1))
}
else{
vibrator.vibrate(500)
}
}
And i called it in the onCreate:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_finish)
vibrate(this@FinishActivity)
I also had to declare the variable again in the onDestroy Method XD and then stopped the vibration
override fun onDestroy() {
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
super.onDestroy()
vibrator.cancel()
}
Solution
private val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
This is failing because it's really a call to context.getSystemService
, and your Activity
doesn't have a context
when it's first constructed, so initialising the variable this way is going to fail (the error you got probably told you this).
There's three main approaches you could take - the first two involve you initialising vibrator
when you do have what you need (a context
in this case), e.g. in onCreate
private var vibrator1: Vibrator? = null
private lateinit var vibrator2: Vibrator
private val vibrator3: Vibrator by lazy {
getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
}
fun onCreate() {
vibrator1 = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
vibrator2 = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
// vibrator3 will assign itself when you first access it
}
So for the first two, you need to set them.
The first one, initialising it to null just because it needs to be set to something when you declare it, is simple - but now vibrator
is nullable, you need to null-check it everywhere, and it's not actually ever supposed to be null, you're using nullability as a workaround, and it's overcomplicating things.
The second, lateinit
, is a promise that you'll set a value on it before anything tries to read it. So you don't need to give it an initial value, you just need to be careful that you assign it early enough. It does have to be a var
instead of a val
now though
The third one, using lazy
, basically initialises the value the first time something accesses it. It's a bit like a lateinit
that assigns itself by running the code in the lambda. And it's a val
! All you need to worry about here is that the first access happens when the lambda can successfully run - in this case, you need that context
. But nothing's accessing vibrator
before the activity has its context, so it's all good
There are pros and cons for these, but it's good to be aware of them. Especially lateinit
, it's Kotlin's way of having its nullability/null-checking system work cleanly for things that can't be initialised immediately, which happens a lot in Android with its lifecycle callbacks
Answered By - cactustictacs
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.