NativeScript / nativescript-angular

Integrating NativeScript with Angular
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
Apache License 2.0
1.21k stars 241 forks source link

Asynchronously setting images #1730

Open nikoTM opened 5 years ago

nikoTM commented 5 years ago

Environment

{N} Playground

Describe the bug

Setting images asynchronously inside a ListView does not work as expected. Images get mixed up. Initially, I thought it was related to recyclerview, but turns out it's the same without it and happens on iOS as well.

To Reproduce Preview the playground link on Android or iOS.

Expected behavior

Images should be displayed correctly (the text below should be the same as the text on images) when the source is being set asynchronously.

Sample project

https://play.nativescript.org/?template=play-ng&id=0IKfFp&v=2

Additional context This is a minimal reproduction for the issue. Images need to be loaded asynchronously because in our project we need to provide additional security headers with these requests.

tsonevn commented 5 years ago

Hi @nikoTM,

In NativeScript we utilize the native controls that do UI Virtualization and Component Recycling. This means only the UI elements for the items visible inside the ListView will be created. These UI elements will be reused to show the new items that come into view. This reuse of the cells inside the ListView component seems to cause this behaviour inside your project. Regarding that, you can review the blog post here, where it is described, how to manage the components state in the ListView.

nikoTM commented 5 years ago

Hi @tsonevn,

Thanks for the response. Unfortunately, I am already aware of the information you have provided. With that in mind, I am still unable to get a ListView to behave with async image sources. If it is possible to somehow achieve that, I believe it would have a complex technical implementation (would love to be wrong here), so much so that it's not readable neither easily digestible for the next dev. This leads me to the conclusion that the problem needs to be addressed on the framework level, especially for a use case that, I assume, is quite common.

knocknarea commented 5 years ago

@tsonevn @nikoTM

Are NativeScript going to do anything to fix this major shortcoming in the framework?

For our application, we are showing a list of user profiles, those profile images are getting jumbled up because of this flaw which is quite serious.

I have observed that visible components (including their state, @Input or otherwise) are overwritten by ‘offscreen’/invisible components and this is a complete NO NO.

I think the fundamental problem here is that the nativescript/angular approach to virtualization it is too eager. Most devices will only show a very limited number of components, virtualization should start with a bank of components that is at least twice that number before reuse happens, that is, N visible components and N offscreen/invisible components. Visible components are sacred and protected from virtualized recycling while visible, the N others are a bank that can be set and switched if needed.

Virtualization should not overwrite any visible component state with that of a component that is currently not visible. Period.

For example:

-- Onscreen --- [Component(1)] <--- This components state will be overwritten by... [Component(2)] [...] [Component(N)] -- Offscreen --- [Component(N+1)] <-- This components state.... [Component(N+2)] ...

What I have seen and I can add to the above sample, when the view is presented:

[Component(1)] image added OK.

Subsequently...

[InvisibleComponent(N+1)] set to point at [Component(1)] and Component(1) is set to whatever content is in [InvisibleComponent(N)]. This is absolutely not anything to do with the underlying virtualization, rather is within the nativescript handling of that virtualization.

The link you provided contains two very controversial suggestions:

a) you publicise private internal state

OR

b) that your components be stateless (i.e mostly useless) for ‘better architecture’

Outside of the most fundamentally simple applications, application components will not only accept @Input() but may generate and in fact rely on internal state derived from that input for the purpose of performing the task they were designed to do. This state may not be of any use, or indeed should not be visible, outside of the component itself. And besides, it’s a pretty straight forward and well understood concept of object orientation. A component/object holding internal state is not a design flaw.