I am programming a live stream function and the button is animated with lottie. I can't find anything wrong on the application but crashlytics shows this.
Fatal Exception: java.lang.StackOverflowError: stack size 8192KB
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.ViewGroup.findViewTraversal(ViewGroup.java:4745)
at android.view.View.findViewById(View.java:24941)
at android.view.Window.findViewById(Window.java:1481)
at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:634)
at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:259)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity.showLiveViewer(HomeActivity.kt:154)
at com.zurdo.presentation.features.home.HomePresenter$onRefreshStatusLive$1$2.invoke(HomePresenter.kt:124)
at com.zurdo.presentation.features.home.HomePresenter$onRefreshStatusLive$1$2.invoke(HomePresenter.kt:120)
at com.zurdo.core.functional.Either.either(Either.kt:28)
at com.zurdo.presentation.features.home.HomePresenter$onRefreshStatusLive$1.invoke(HomePresenter.kt:120)
at com.zurdo.presentation.features.home.HomePresenter$onRefreshStatusLive$1.invoke(HomePresenter.kt:119)
at com.zurdo.core.interactor.UseCase$invoke$2$1.invokeSuspend(UseCase.kt:17)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7680)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Here is the code
Activity_main.xml:
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/btnLiveUser"
android:layout_width="0dp"
android:layout_height="60dp"
android:elevation="10dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:visibility="gone"
app:layout_constraintTop_toTopOf="@id/goToStoreButton"
app:layout_constraintEnd_toStartOf="@+id/goToStoreButton"
app:layout_constraintStart_toEndOf="@id/publicationsButton"
app:layout_constraintBottom_toBottomOf="@id/goToStoreButton"
app:lottie_rawRes="@raw/btn_live_1"/>
HomeActivity.kt:
package com.zurdo.presentation.features.home
import android.animation.Animator
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.install.InstallState
import com.google.android.play.core.install.InstallStateUpdatedListener
import com.google.android.play.core.install.model.InstallStatus
import com.zurdo.R
import com.zurdo.core.exception.Failure
import com.zurdo.core.extension.getDynamicLinkId
import com.zurdo.core.platform.BaseActivity
import com.zurdo.core.platform.Constants
import com.zurdo.core.platform.NavigationHelper
import com.zurdo.core.platform.PreferenceHelper
import com.zurdo.data.models.Publication
import com.zurdo.data.models.User
import com.zurdo.presentation.ZurdoApp
import com.zurdo.presentation.features.onboarding.OnboardingActivity
import com.zurdo.presentation.features.publicationDetail.publicationExtra
import com.zurdo.presentation.features.publications.PublicationListFragment
import com.zurdo.presentation.features.publications.pubDetaiRequestCode
import com.zurdo.presentation.features.support.supportRequestCode
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.custom_search_field.*
import java.util.*
import javax.inject.Inject
import com.zurdo.presentation.features.publications.ReqCodeComments
import com.zurdo.presentation.features.videostream.HOST
import com.zurdo.presentation.features.videostream.IS_LIVE
const val publicationListFragmentTag: String = "publicationListFragment"
class HomeActivity : BaseActivity(),
HomeContract.View {
private val UPDATE_CODE: Int = 100
private lateinit var appUpdateManager: AppUpdateManager
@Inject
lateinit var presenter: HomeContract.Presenter
private lateinit var publicationListFragment: PublicationListFragment
@Inject
lateinit var preferences : PreferenceHelper
private val manager: FragmentManager = supportFragmentManager
override fun layoutId() = R.layout.activity_main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ZurdoApp.component.inject(this)
if(!preferences.getBoolean(Constants.SPKEY_IS_NOT_FIRST_LAUNCH)){
startActivity(Intent(this, OnboardingActivity::class.java))
}
presenter.view = this
presenter.onCreate()
btnLiveUser.setOnClickListener {
goToStreamViewer()
}
//intent?.let {
// val isLive = intent.getStringExtra("title") == "Zurdo is live testing!" //TODO(Temporal validation)
//
//}
}
private fun goToStreamViewer() {
NavigationHelper.goToStreamView(this, false)
}
override fun goToStreamView() {
NavigationHelper.goToStreamView(this, true)
}
override fun onNewIntent(intent: Intent?) {
if (intent?.getBooleanExtra(HOST, true) == false) {
if (intent.getBooleanExtra(IS_LIVE, false)) {
presenter.verifyLiveActive()
goToStreamViewer()
}
}
if (!preferences.userToken.isNullOrEmpty()) {
intent.getDynamicLinkId { id, isPotCast ->
goToPublication(id, isPotCast)
this.intent = null
}
}
super.onNewIntent(intent)
}
override fun showLiveHost() {
goToLiveButton.isVisible = true
ivBtnLive.isVisible = true
}
override fun showLiveViewerTemporal() {
btnLiveUser.isVisible = true
tvLiveUser.isVisible = true
}
override fun onResume() {
super.onResume()
presenter.onRefreshStatusLive()
//checkIfUserIsPremium()
//appUpdateManager = AppUpdateManagerFactory.create(this)
//
//// Returns an intent object that you use to check for an update.
//val appUpdateInfoTask = appUpdateManager.appUpdateInfo
//
//// Checks that the platform will allow the specified type of update.
//appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
// if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
// try {
// appUpdateManager.startUpdateFlowForResult(
// appUpdateInfo,
// AppUpdateType.IMMEDIATE,
// this,
// UPDATE_CODE
// )
// } catch (e: IntentSender.SendIntentException) {
// e.printStackTrace()
// }
// }
//}
if (!preferences.userToken.isNullOrEmpty()) {
intent.getDynamicLinkId { id, isPotCast ->
goToPublication(id, isPotCast)
intent = null
}
}
}
override fun showLiveViewer(show: Boolean) {
if(show) {
btnLiveUser.addAnimatorUpdateListener {
tvLiveUser.isVisible = (btnLiveUser.progress * 100).toInt() < 90
}
btnLiveUser.addAnimatorListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { println() }
override fun onAnimationEnd(p0: Animator?) {
btnLiveUser.playAnimation()
}
override fun onAnimationCancel(p0: Animator?) { println() }
override fun onAnimationRepeat(p0: Animator?) { println() }
})
btnLiveUser.playAnimation()
} else {
btnLiveUser.removeAllAnimatorListeners()
btnLiveUser.pauseAnimation()
}
btnLiveUser.isVisible = show
tvLiveUser.isVisible = show
}
private fun checkIfUserIsPremium(){
if(preferences.isUserPremium)
layoutProfileButton.background = resources.getDrawable(R.drawable.bg_profile_border)
else{
layoutProfileButton.background = null
}
}
override fun onDestroy() {
presenter.onDestroy()
super.onDestroy()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == supportRequestCode && resultCode == Activity.RESULT_OK) {
notify(R.string.sent_support_contact_text, coordinator)
}else if(requestCode == pubDetaiRequestCode){
//publicationListFragment.presenter.onHomeTapped()
//publicationListFragment.presenter.fetchPublications(isHome = false, withProgress = false)
//publicationListFragment.presenter.refreshPublications(false)
publicationListFragment.updatePublication((data?.getSerializableExtra(publicationExtra) as Publication))
}else if(requestCode == ReqCodeComments){
publicationListFragment.updatePublication((data?.getSerializableExtra(publicationExtra) as Publication))
}
}
override fun setupView() {
publicationListFragment = PublicationListFragment.newInstance()
manager.beginTransaction()
.replace(
R.id.containerLayout,
publicationListFragment,
publicationListFragmentTag
)
.commit()
searchButton.setOnClickListener {
presenter.onShowSearchField(true)
}
closeButton.setOnClickListener {
presenter.onShowSearchField(false)
}
profileButton.setOnClickListener {
presenter.onProfileButtonTapped()
}
goToStoreButton.setOnClickListener {
presenter.onGoToStoreTapped()
}
goToLiveButton.setOnClickListener { presenter.onGoToStreamTapped() }
publicationsButton.setOnClickListener {
//publicationListFragment.presenter.onSearchPublicationsByFilter()
publicationListFragment.presenter.onHomeTapped()
//publicationListFragment.presenter.fetchPublications(isHome = true, withProgress = true)
}
premiumButton.setOnClickListener {
presenter.onGoToStoreTapped()
}
logoHomeBtn.setOnClickListener{
publicationListFragment.presenter.onHomeTapped()
}
/*
publicationsButton.setOnTouchListener(OnTouchListener { v, me ->
if (me.action == MotionEvent.ACTION_DOWN) {
} else if (me.action == MotionEvent.ACTION_MOVE) {
val params = ViewGroup.LayoutParams(
v.width,
v.height,
(me.rawX - v.width / 2).toInt(),
(me.rawY - v.height).toInt()
)
v.layoutParams = params
}
true
})
*/
searchField.setOnEditorActionListener(object : TextView.OnEditorActionListener {
override fun onEditorAction(p0: TextView?, p1: Int, p2: KeyEvent?): Boolean {
if (p1 == EditorInfo.IME_ACTION_SEARCH) {
p0?.text.toString().let {
presenter.onSearchPublications(it.toLowerCase(Locale.getDefault()))
}
return true
}
return false
}
})
}
override fun showCustomSearchField(show: Boolean) {
customSearchField.visibility = if (show) View.VISIBLE else View.GONE
searchField.setText("")
if (show) {
searchField.requestFocus()
showKeyboard()
} else {
hideKeyboard()
//publicationListFragment.presenter.fetchPublications(withProgress = false)
publicationListFragment.presenter.refreshPublications()
}
}
override fun showProfilePicture(user: User?) {
user?.let {
Glide.with(this)
.load(it.profileUrl)
.transform(CircleCrop())
.into(profileButton)
checkIfUserIsPremium()
}
}
override fun goToStoreView() = NavigationHelper.goToStoreView(this)
override fun goToProfileView() {
NavigationHelper.goToProfileView(this)
}
override fun searchPublications(filter: String) {
hideKeyboard()
publicationListFragment.presenter.onSearchPublicationsByFilter(filter)
}
override fun handleFailure(failure: Failure) {
val message = when (failure) {
Failure.DatabaseError -> R.string.unable_to_get_user
else -> R.string.general_error_text
}
notify(message, coordinator)
}
var appUpdatedListener: InstallStateUpdatedListener = object : InstallStateUpdatedListener {
override fun onStateUpdate(installState: InstallState) {
if (installState.installStatus() == InstallStatus.DOWNLOADED) {
notify(R.string.app_update_downloaded,coordinator)
} else if (installState.installStatus() == InstallStatus.INSTALLED) {
appUpdateManager.unregisterListener(this)
}
}
}
private fun goToPublication(id: Int, isPotCast: Boolean) {
if (isPotCast) NavigationHelper.goToPublicationDetailPodcastView(this, id, 2091)
else NavigationHelper.goToPublicationDetailView(this, id, 2091)
}
}
Could someone help telling me how to reproduce the issue and solve it? Thanks in advance
I have tried making multiple calls to overload the memory stack but nothing happened
Looking at your stacktrace, we see this recurring bit:
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity$showLiveViewer$2.onAnimationEnd(HomeActivity.kt:147)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at com.airbnb.lottie.utils.BaseLottieAnimator.notifyEnd(BaseLottieAnimator.java:74)
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
at com.airbnb.lottie.LottieAnimationView.playAnimation(LottieAnimationView.java:599)
at com.zurdo.presentation.features.home.HomeActivity.showLiveViewer(HomeActivity.kt:154)
So you're stuck in a loop because of the code that calls playAnimation in onAnimationEnd:
override fun onAnimationEnd(p0: Animator?) {
btnLiveUser.playAnimation()
}
That call to the LottieDrawable is immediately triggering a call to end animation, so your callback gets called, which calls playAnimation
, which immediately ends the animation, etc, etc:
at com.airbnb.lottie.utils.LottieValueAnimator.endAnimation(LottieValueAnimator.java:221)
at com.airbnb.lottie.LottieDrawable.playAnimation(LottieDrawable.java:593)
So why is this?
Looking at the source code for that class, we see:
...
if (!animationsEnabled()) {
setFrame((int) (getSpeed() < 0 ? getMinFrame() : getMaxFrame()));
animator.endAnimation(); // <-- KEY BIT HERE
if (!isVisible()) {
onVisibleAction = OnVisibleAction.NONE;
}
}
...
So it seems Lottie calls the animation end callback immediately if the animation is actually disabled. OK. So why is your animation disabled? Again, according to the source code:
private boolean animationsEnabled() {
return systemAnimationsEnabled || ignoreSystemAnimationsDisabled;
}
So it seems animations are disabled if the Android system animations are disabled and you haven't told Lottie to ignore that.
So it would seem that your crash occurs when you disable system animations. This should be easy to test and confirm.