Skip to content

ListView not updating on Android #3193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
johnnyzen opened this issue Nov 28, 2016 · 15 comments
Closed

ListView not updating on Android #3193

johnnyzen opened this issue Nov 28, 2016 · 15 comments

Comments

@johnnyzen
Copy link

Tell us about the problem

The listview on Android behaves oddly when updating elements on particular rows, using Angular and TS, Observable and ObservableArray

Which platform(s) does your issue occur on?

Android Only

Please provide the following version numbers that your issue occurs with:

{
"description": "NativeScript Application",
"license": "SEE LICENSE IN ",
"readme": "NativeScript Application",
"repository": "",
"nativescript": {
"id": "org.nativescript.nativescriptexperimentts",
"tns-android": {
"version": "2.3.0"
},
"tns-ios": {
"version": "2.3.0"
}
},
"scripts": {
"build": "tns run android --device 1 --watch",
"livesync": "tns livesync android --device 1 --watch"
},
"dependencies": {
"@angular/common": "2.1.2",
"@angular/compiler": "2.1.2",
"@angular/core": "2.1.2",
"@angular/forms": "2.1.2",
"@angular/http": "2.1.2",
"@angular/platform-browser": "2.1.2",
"@angular/platform-browser-dynamic": "2.1.2",
"@angular/router": "3.1.2",
"nativescript-angular": "1.1.3",
"nativescript-theme-core": "^0.2.1",
"reflect-metadata": "~0.1.8",
"rxjs": "5.0.0-beta.12",
"tns-core-modules": "2.4.0",
"typed-event-emitter": "^1.0.3",
"typescript-collections": "^1.2.3"
},
"devDependencies": {
"babel-traverse": "6.19.0",
"babel-types": "6.19.0",
"babylon": "6.14.1",
"lazy": "1.0.11",
"nativescript-dev-android-snapshot": "^0..",
"nativescript-dev-typescript": "^0.3.2",
"typescript": "^2.0.10",
"zone.js": "~0.6.21"
}
}

Please tell us how to recreate the issue in as much detail as possible.

  1. Clone repo https://github.com/johnnyzen/NativeScript-Issue
  2. Run the project on Android
  3. Click the Add button to add a row
  4. You should see a counter on the row just added increment by 1
  5. Add another row using the Add button. Again this newly added row should also have a counter incrementing by 1.
  6. Now keep pressing the "Press Me" on the first row until the counter reaches 0
  7. When the first row counter reaches zero, the rest of the list items stop updating

Expected Behaviour

The rest of the items should continue to update as usual.
THIS WORKS FINE ON IOS

@tsonevn tsonevn self-assigned this Nov 29, 2016
@tsonevn
Copy link
Contributor

tsonevn commented Nov 29, 2016

Hi @johnnyzen,
Thank you for your interest in NativeScript and for your sample project.

I reviewed the app and tested it with latest NativeScript 2.4, however was unable to reproduce the described problem. Could you verify, whether your are using latest NativeScript, while using tns --version and to upgrade it if it is necessary. I have notice that your are using old tns-android. Instructions, how to upgrade, could be found here. After upgrade you should also remove the platform tns platform remove <platform_name> and then to delete node_modules and platforms folders.

Let me know, whether this helps or if I could assist you further

@johnnyzen
Copy link
Author

Great news! Many thanks for your reply, updating has fixed the issue... out of interest, do you know what the issue was ? Had a look at the release notes, but couldnt see... Just curious.

Thanks again!

Best

@johnnyzen johnnyzen reopened this Nov 29, 2016
@johnnyzen
Copy link
Author

johnnyzen commented Nov 29, 2016

Hi all, Sorry I have reopened as we managed to recreate on the latest version.

As crazy as it sounds, we noticed the problem returns if we remove: height="100%"

from : <ListView [items]="items" height="100%" >

(from the sample project app.component.html (https://github.com/johnnyzen/NativeScript-Issue)

Any ideas whats happening here?

The reason why we set the height here, was we noticed a problem with running it on iOS - The listview didnt seem to expand correctly when we added a new row.

@johnnyzen
Copy link
Author

We also noticed the rows were stopping being updated when off screen and then scroll to become visible. Here is another project demoing where no height exists, and testing using different types of views : https://github.com/brins0/nativescript-experiment-ts

@tsonevn
Copy link
Contributor

tsonevn commented Nov 30, 2016

Hi @johnnyzen,

In the iOS you should add GridLayout as a main container of the ListView, which will allow the component to set the right height of the component. Setting this Layout should also resolve your problem with updating the value of all ListView items. Could you verify, whether this will resolve your problem.

Sample

<GridLayout>
        <ListView [items]="items">
            <template let-item="item">
                <counter [model]="item"></counter>
            </template>
        </ListView>
    </GridLayout>

Regards,
@tsonevn

@brins0
Copy link

brins0 commented Nov 30, 2016

Heya @tsonevn,

I'm working with @johnnyzen on this too. I've wrapped the ListView in a GridLayout and it doesn't seem to make any difference to our problem on Android. Is the below what you meant to do?

<StackLayout orientation="vertical">
    <StackLayout orientation="horizontal">
        <Button verticalAlignment="center" text="Add" (tap)="onTapAdd()"></Button>
        <Button verticalAlignment="center" text="Remove" (tap)="onTapRemove()"></Button>
        <Button verticalAlignment="center" text="Increase All" (tap)="onTapIncreaseAll()"></Button>
        <Label verticalAlignment="center" text="{{ validItems }}"></Label>
    </StackLayout>
    <GridLayout>
        <ListView [items]="items">
            <template let-item="item">
                <counter [model]="item"></counter>
            </template>
        </ListView>
    </GridLayout>
</StackLayout>

I'm basing this on the repo @johnnyzen mentioned before: https://github.com/brins0/nativescript-experiment-ts

As soon as the first element in the list stops updating (when the timer reaches zero), all the other elements in the list stop updating. Updating the first element or adding/removing from the list then causes all other elements to be updated. Moving the element out of the viewport then back in also causes the elements to update as they come back into view.

The models are still representing the correct data though.

@brins0
Copy link

brins0 commented Nov 30, 2016

I've made another handful of changes to the layouts and added text box to further show the issues we're having. If you add enough items to make the list scroll, selecting a text box then scrolling produces really odd effects showing duplicate selections further down the list. The position text appears in also messes up. It now logs the output of the model with its message so you can see the models themselves are updating behind the scenes.

I think there's an issue with the recycling of items in the list view after talking to some of our native guys, though I'm not an expert in the low level native functionality like @johnnyzen is...

@tsonevn
Copy link
Contributor

tsonevn commented Dec 1, 2016

Hi @brins0,
I reviewed again the app from https://github.com/brins0/nativescript-experiment-ts and the suggestion for using GridLayout seems to work in our local Android emulator. Could you try to delete node_modules, platforms and hooks folder from the project. You could also clear npm cache, while using npm cache clear. Make sure also to remove the app from the emulator or device, where you are deploying your app. If this does not help, could you provide more info about the Android device or Emulator and Android API level.

Regards,
@tsonevn

@brins0
Copy link

brins0 commented Dec 1, 2016

Doing all of the above still hasn't resolved the issue for us. Here's some details for our test device:

  • Model number: Nexus 5X
  • Android version: 7.0
  • Android security patch level: 5 August 2016
  • Kernel version: 3.10.73-g43154bf android-build@vpec5.mtv.corp.google.com url correction #1 Tue Jun 28 20:09:05 UTC 2016
  • Build number: NRD90M
  • Google Play Services version: 10.0.84 (440-1377495526)

It also happens on my personal phone, here's details for that:

  • Model number: ONEPLUS A3003
  • Android version: 6.0.1
  • Android security patch level: 1 September 2016
  • Kernel version: 3.18.20-perf+ OnePlus@ubuntu-21 url correction #1 Fri Sept 30 14:06:43 CST 2016
  • Build number: ONEPLUS A3003_16_160930
  • Google Play Services version: 10.0.84 (448-137749526)

As an additional debugging note, I've found anything changing anything in a model bound to a component which isn't in view which then comes into view in a ListView is effected by this issue. Adding a new counter component in programmatically when starting the app produces the same symptoms.

@nsndeck
Copy link

nsndeck commented Dec 2, 2016

Hi all,

I've investigated this issue with the project from here and the problem is visible with the latest version (if you remove GridLayout that wraps the ListView control). However the problem comes from the fact that native Android ListView control gives a visual items in an unpredictable order (when placed in a container with an unspecified height like StackLayout). I'll try to explain:

With the first tap on a button Add, one DataModel is added to the collection. The interesting part is what happens on the background. Since ListView.items collection is changed ListView should update its UI - therefore creates a new item (counter.component) for added DataModel instance. This view is new and its angular representation has not been checked and ngOnInit method is called after first check. Here code subscribes for its DataModel changes and update counter. So far so good.
With the second tap, another DataModel is added to collection. Here ListView again is trying to update UI, so it is trying to create views for both items. Unfortunately due to (a little bit weird logic (imo)) inside native Android ListView recycling logic it creates a new view for DataModel at 0 (first) inside data.collection and this view is clean and angular calls ngOnInit for it again, so code again subscribes for changes of data.collection[0]. Most interesting part is that when creating view for data.collection[1] item Android ListView returns the view that was previously used for data.collection[0], but this view has been checked for changes and its ngOnInit is not called.

The solution is very simple just to be strict on MVVM pattern. As it turns out ngOnInit is part of the view part. I've made a fix for the problem - making subscription when input property model is changed. A sample code is worth a thousand words:

// counter.component.ts
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from "@angular/core";
import DataModel from '../../models/data.model';

@Component({
    moduleId: module.id,
    selector: "counter",
    templateUrl: "counter.component.html",
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class CounterComponent {

    private _model: DataModel;
    private modelChangeHandler: (args) => void = (args) => {
        this.cd.markForCheck();
    };

    @Input()
    set model(model: DataModel) {
        if (this._model) {
            this._model.off(DataModel.propertyChangeEvent, this.modelChangeHandler);
        }
        this._model = model;
        this._model.on(DataModel.propertyChangeEvent, this.modelChangeHandler);
    }
    get model() { return this._model; }
    
    constructor(private cd: ChangeDetectorRef) {
    }

    onTap() {
        this.model.increaseCounter();
    }
}

@tsonevn tsonevn closed this as completed Dec 5, 2016
@johnnyzen
Copy link
Author

Many thanks for the replies and investigation. I'm fairly new to this world, but I am sure @brins0 will be most pleased.

@divyachandana
Copy link

Refresh radlistview nativescript on updating data
radlistview refresh
<RadListView #myListView></RadListView>

@ViewChild("myListView") listViewComponent: RadListViewComponent;
//use this whenever you update data in dataItems
this.listViewComponent.listView.refresh();

@nileshmean
Copy link

Refresh Listview not working
`

</StackLayout> 
<ScrollView class="page">
		<!-- <SearchBar width="250" hight="50" hint="Search hint" [text]="searchPhrase" (submit)="onSearchSubmit($event)"></SearchBar> -->


 <!-- <StackLayout class="form">
				<SearchBar [formControl]="searchControl" class="input"></SearchBar>
			</StackLayout>  -->
	

	<ListView id="listview"  pullToRefresh="true"  [items]="_batches" (itemTap)="onItemTap($event)" class="list-group">
	
		<ng-template let-comment="item" let-i="index" let-odd="odd" let-even="even">
		
			<StackLayout orientation="horizontal" class="list-group-item" >
				
					<StackLayout width="200" height="45">
							<Label  horizontalAlignment="left" [text]="comment.companyname" textWrap="true" ></Label>
		  					<Label  horizontalAlignment="left" [text]="comment.phonenumber" textWrap="true"></Label>
					</StackLayout>
					<StackLayout width="60">
							<Button  horizontalAlignment="right" class="edit-button" text="" (tap)="EditModal(comment._id)"></Button>
					</StackLayout> 
					<StackLayout  horizontalAlignment="right" width="60">
							<Button class="delete-button" text="" (tap)="DeleteItem(comment._id)"></Button>
					</StackLayout> 
			
								



            </StackLayout>

		</ng-template>
	</ListView> 
</ScrollView>
` On ts file ``` var listview:ListView= this.page.getViewById("listview"); listview.refresh(); ``` After

@nileshmean
Copy link

@divyachandana do you have any option to refresh list view

@lock
Copy link

lock bot commented Apr 25, 2020

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked and limited conversation to collaborators Apr 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants