av.imageview
av.imageview copied to clipboard
fix(android): use application context
There is a possible crash when loading images in a very early stage of the application lifetime:
[ERROR] TiExceptionHandler: (main) [17,95396] /alloy/controllers/settings/index.js:367
[ERROR] TiExceptionHandler: Error: You cannot start a load for a destroyed activity
[ERROR] TiExceptionHandler: at Window.onFocus (/alloy/controllers/my-controller/index.js:100:20)
[ERROR] TiExceptionHandler: at Window.value (ti:/kroll.js:1604:27)
[ERROR] TiExceptionHandler: at Window.value (ti:/kroll.js:1656:25)
[ERROR] TiExceptionHandler:
[ERROR] TiExceptionHandler: com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed(RequestManagerRetriever.java:317)
[ERROR] TiExceptionHandler: com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:128)
[ERROR] TiExceptionHandler: com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:108)
[ERROR] TiExceptionHandler: com.bumptech.glide.Glide.with(Glide.java:776)
[ERROR] TiExceptionHandler: av.imageview.ImageViewHelper.prepareGlideClientFor(ImageViewHelper.java:53)
[ERROR] TiExceptionHandler: av.imageview.AvImageView.setImageAsURL(AvImageView.java:171)
[ERROR] TiExceptionHandler: av.imageview.AvImageView.processProperty(AvImageView.java:116)
[ERROR] TiExceptionHandler: av.imageview.AvImageView.propertyChanged(AvImageView.java:79)
[ERROR] TiExceptionHandler: org.appcelerator.kroll.KrollProxy.firePropertyChanged(KrollProxy.java:992)
[ERROR] TiExceptionHandler: org.appcelerator.kroll.KrollProxy.onPropertyChanged(KrollProxy.java:1087)
[ERROR] V8Exception: Exception occurred at /alloy/controllers/settings/index.js:367: Uncaught Error: You cannot start a load for a destroyed activity
Actually, I am not sure about this fix anymore. The linked SO-post also suggests NOT to use it below the linked answer. Maybe use the activity by default and use the application context if the activity is null
? @m1ga, @prashantsaini1 and @jquick-axway, I hope it's okay to tag you here. It would be very interesting to get your feedback on this!
Can you reproduce it? I wonder if it is not just trying to load it in an old window so just a proxy null
check at the beginning would be enough so it won't continue to load the image.
Or is it really in the current open window?
In my opinion, you should always use the activity the ViewProxy
is attached to (ie: the Ti.UI.Window
it's attached to). That said, note that when the parent activity/window closes, the activity the proxy references will be in a destroyed state. It sounds like this crash is happening when you set the "image" property after the window has been closed? If so, then maybe you just need to guard against this by calling the activity's isDestroyed() method and just return out when it's in this state since the view isn't being displayed anymore.
For example, Titanium checks if an AlertDialog's parent activity hasn't been destroyed before showing it. Also note we check isFinishing()
too, which means the activity is in the middle of being closed/destroyed.
https://github.com/appcelerator/titanium_mobile/blob/master/android/modules/ui/src/java/ti/modules/titanium/ui/widget/TiUIDialog.java#L356
It happens when switching between light- and dark mode via the Android setting, really interesting behavior. Maybe that's the underlaying issue instead.
Switching between dark/light theme causes the activity to be destroyed and recreated with the new "context" containing the new theme info. This is how it works natively. This causes all of the destroyed activity's views to be released and new views will be created for the new activity with the new theme. In Titanium, the proxies will be kept alive, but they're forced to recreate a new view. Regarding "av.imageview", an ImageViewProxy instance's getView()
method will be called a 2nd time when the theme changes because it's forced to create a new view.
@hansemannn , it sounds like your app is attempting to change the "av.imageview" image property during this theme switch. Just put the if-check in the view and you'll be fine because there is no point in updating a view that belongs to a destroyed activity. Your property change is still stored by the proxy and will be respected when a new view has been created for the new activity.
I hope what I said above makes sense.
Thank you Josh, that was really helpful and makes sense!
I added a null-check to the activity, but unfortunately, it's not null, just "destroyed". Or do you mean I should do an if-check of the activity in Titanium?
Did you try to use https://developer.android.com/reference/android/app/Activity#isDestroyed() ?
And also perhaps check if proxy
is null as mentioned earlier. Otherwise it could crash at the proxy.getActivity()
@m1ga is right. You need to add a check for isDestroyed()
because its Glide that's throwing an exception due to using a destroyed activity.
if ((activity == null) || activity.isFinishing() || activity.isDestroyed()) {
return;
}