Issue
I can't figure out what is wrong in here, looks like Timer is causing this issue but even if I remove Timer line completely it still crashing with error like thi "Only the original thread that created a view hierarchy can touch its views."
Maybe you guys can suggest a different way to run animations inside of an activity to avoid this.
Another interesting thing is that it runs perfectly fine on Android 12, but crashing on Android 7.
Here is the code that sitting inside of Activity:
private fun setAnimations() {
fadeInErrorMessage.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {
binding.mainErrorMessageContainer.visibility = View.VISIBLE
}
override fun onAnimationEnd(animation: Animation) {
Timer("ErrorMessage", false).schedule(1500L) {
binding.mainErrorMessageContainer.startAnimation(fadeOutErrorMessage)
}
}
override fun onAnimationRepeat(animation: Animation) {}
})
fadeOutErrorMessage.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
binding.mainErrorMessageContainer.visibility = View.INVISIBLE
errorMessageAnimationIsRunning = false
}
override fun onAnimationRepeat(animation: Animation) {}
})
}
Here is logs:
2022-09-14 21:24:22.981 17059-17371/com.company.app E/AndroidRuntime: FATAL EXCEPTION: ErrorMessage
Process: com.company.app, PID: 17059
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6892)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1083)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:5205)
at android.view.View.invalidateInternal(View.java:13657)
at android.view.View.invalidate(View.java:13621)
at android.view.View.startAnimation(View.java:20175)
at com.company.app.ui.main.MainActivity$setAnimations$1$onAnimationEnd$$inlined$schedule$1.run(Timer.kt:149)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Solution
Just run your animations inside runOnUiThread()
:
runOnUiThread(new Runnable() {
void run() {
binding.mainErrorMessageContainer.visibility = View.VISIBLE
}
});
runOnUiThread(new Runnable() {
void run() {
binding.mainErrorMessageContainer.startAnimation(fadeOutErrorMessage)
}
});
Edit: it looks like your specific error refers to the onAnimationEnd, where you're running Timer.schedule(). So you should try to make that method look like this:
override fun onAnimationEnd(animation: Animation) {
Timer("ErrorMessage", false).schedule(1500L) {
runOnUiThread(new Runnable() {
void run(){
binding.mainErrorMessageContainer.startAnimation(fadeOutErrorMessage)
}
});
}
}
Answered By - user496854
Answer Checked By - Terry (JavaFixing Volunteer)