Closed felixkrautschuk closed 2 years ago
I have the same issue any workaround?
This is still an issue using nativescript-ui-listview latest 9.1.4 and NS 8. Updated sample app with latest dependencies: ns-rlv-issue-android.zip
We had accidentally updated to 9.1.4 in our production app and we have seen that the amount of crashes heavily increased. So there must be other situations than pull-to-refresh where this issue occurs as well, as not that many people use the pull-to-refresh feature. After downgrading to 9.0.4 the number of crashes immediately decreased again, so this version is the last working version on our side.
It would really help to see what changes where made between 9.0.4 and 9.1.0.
Just checked out nativescript-ui-listview@10.0.0, but unfortunately the issue is still existing
updated demo app with latest dependencies and new observations ns-rlv-issue-android.zip
I noticed, that this issue is NOT related to the pull-to-refresh functionality of the RadListView component on Android...
Instead, the issue occurs when removing all items in the ObserableArray (the datasource of the RadListView) and adding new items to it.
export function updateItems() {
setTimeout(() => {
//clearing datasource
vm.get("items").splice(0, vm.get("items").length);
//adding new items
vm.get("items").push([{id: 99, title: "Item with id 99"}, ..., ...]);
}, 500);
}
After doing that, the new items are visible, but when tapping an item of the ListView, args.view is undefined.
https://user-images.githubusercontent.com/6443021/131102415-b6b6059b-7a8b-40cf-a423-b168b702c678.mov
It does not matter in which way I am clearing the ObservableArray, so the issue occurs the same when:
When I leave at least one item in the ObservableArray and add the new items afterwards, everything works as expected (vm.get("items").splice(0, vm.get("items").length); or listview.items.length = 1;)
When clearing ALL items of the ObservableArray and calling listview.refresh() afterwards, the issue does not occur. But then the usage of the ObservableArray has no meaning anymore, if I need to call the refresh method all the time.
Clearing a list and filling it with new items should be a common use-case and in addition, ALL of that was working as expected with nativescript-ui-listview 9.0.4
Updated demo app with latest dependencies: see beginning of this comment
I made some furher investigations and noticed, that accessing the view from the event data of itemTap, itemHold etc is working as expected after loading the data items into the RadListView for the first time. The ListViewAdapter contains 9 viewHolders as expected.
I am logging it like this in the itemLoading-event:
export function onItemLoading(args: ListViewEventData) {
...
if(isAndroid) {
console.log("viewHolders count:");
// @ts-ignore
console.log(args.object._android._listViewAdapter._viewHolders.length);
}
}
When removing all items of the ObservableArray (splice) and adding new items to it like this:
//main-page.ts
export function updateItemsAsync() {
setTimeout(() => {
vm.get("items").splice(0, vm.get("items").length);
const newItems = [];
for(let i = 1000; i < 1050; i++) {
newItems.push({id: i, title: "Async item with id " + i});
}
vm.get("items").push(newItems);
}, 1000);
}
... the views and their corresponding bindingContext are also accessible within the itemLoading event, however the viewHolders element of the ListViewAdapter is now an empty list and now events like itemTap or itemHold return undefined for the view element of the event data
//node_modules/nativescript-ui-listview/index.android.js
ListViewItemClickListenerImpl.prototype.onItemClick = function (itemPosition, motionEvent) {
//...
var item = listView.getItemAtIndex(originalPosition);
var tappedView = listView._listViewAdapter.getViewForItem(item); //--> undefined, because this._listViewAdapter._viewHolders is empty
//...
};
//node_modules/nativescript-ui-listview/index.android.js
ListViewAdapter.prototype.getViewForItem = function (item) {
for (var i = 0; i < this._viewHolders.length; i++) { //for loop is getting skipped, as viewHolders is empty array
if (this._viewHolders[i]['nsView'] && this._viewHolders[i]['nsView'].bindingContext === item) {
return this._viewHolders[i]['nsView'].getChildAt(0);
}
}
return undefined;
};
When scrolling the RadListView, the viewHolders list is getting filled with 3 or 4 items and the itemTap, itemHold, (...) events are returning the correct view and its bindingContext for those items, but still undefined for the other items.
https://user-images.githubusercontent.com/6443021/133612367-5d8ea116-e83d-402e-b17e-ee5efe64c061.mov
By the way, the behaviour is exactly the same if the addition of the list items is done synchronously (without setTimeout).
I noticed that the new rangeAdd functionality introduced in version 9.1.0 seems to cause this issue somehow:
_nodemodules/nativescript-ui-listview/index.android.js
onSourceCollectionChanged(data) {
...
if (this._listViewAdapter) {
...
else if (data.action === ChangeType.Add) {
if (isNaN(data.index)) {
this._listViewAdapter.rangeAdd(data.addedCount);
this._currentId += data.addedCount;
}
else {
this._listViewAdapter.rangeAdd(data.index, data.addedCount);
this._currentId += data.addedCount;
}
}
...
}
}
At least I do not get this issue anymore, when replacing that part with the code from nativescript-ui-listview 9.0.4:
onSourceCollectionChanged(data) {
...
if (this._listViewAdapter) {
...
else if (data.action === ChangeType.Add) {
for (let i = 0; i < data.addedCount; i++) {
if (isNaN(data.index)) {
this._listViewAdapter.add(new java.lang.Integer(this._getUniqueItemId()));
} else {
this._listViewAdapter.add(data.index, new java.lang.Integer(this._getUniqueItemId()));
}
}
}
...
}
}
It is hard to say why that rangeAdd stuff should cause this issue, as we have no access to the native com.telerik.widget.list.ListViewAdapter package.
So it would be great if @NathanWalker @triniwiz @rigor789 or whoever is working on the RadListView could have a look at this. Right now we are still fine with nativescript-ui-listview 9.0.4, but it would be better to be able to upgrade to the latest dependencies.
Demo app with latest dependencies: ns-rlv-issue-android.zip
@NathanWalker @triniwiz @rigor789
the issue does NOT occur, when keeping at least one item in the list during splice, like this:
vm.get("items").splice(1, vm.get("items").length);
I guess that this rangeAdd functionality does something special if the list items are empty before adding new items, but I have no idea why and without access to the native sources behind the RadListView it is hard to further invesigate and to provide a pull-request
@NathanWalker @triniwiz @rigor789 Any progress on fixing this?
@OPADA-Eng @felixkrautschuk has kindly contributed a fix, we'll be releasing it early next week (or today/tomorrow, depending on time) and ping back here once it's out.
Edit: try nativescript-ui-listview@10.0.1
It works! Thanks
Please, provide the details below:
Tell us about the problem
When using a RadListView with pullToRefresh on Android, an app crashes when initiating the pullToRefresh operation and after that tapping an item, because args.view is getting undefined after the pullToRefresh.
See the GIF to understand:
This is what I am doing:
(In this sample app, the pull-to-refresh is simply removing the items from ObservableArray and pushing the same items again...)
When trying to access the bindingContext of the view inside itemTap-event, the app crashes:
This issue is NOT happening on iOS and it was working as expected on Android when using NS 6 with RadListView 8.2.0. After upgrading to NS 7 using multiple @nativescript/core versions and using RadListView 9.1.0, this issue occurs.
Which platform(s) does your issue occur on?
Android (multiple versions)
Please provide the following version numbers that your issue occurs with:
Please tell us how to recreate the issue in as much detail as possible.
Is there code involved? If so, please share the minimal amount of code needed to recreate the problem.
ns-rlv-issue-android.zip