Skip to content

Commit 845ef09

Browse files
committed
fix(collection,android): prevent memory leaks (keeping references to viewHolders)
1 parent f080822 commit 845ef09

File tree

1 file changed

+36
-52
lines changed

1 file changed

+36
-52
lines changed

src/collectionview/index.android.ts

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
ChangedData,
55
ContentView,
66
CoreTypes,
7-
FlexboxLayout,
87
Property,
98
ProxyViewContainer,
109
Trace,
@@ -18,15 +17,7 @@ import {
1817
profile
1918
} from '@nativescript/core';
2019
import { layout } from '@nativescript/core/utils/utils';
21-
import {
22-
CollectionViewItemDisplayEventData,
23-
CollectionViewItemEventData,
24-
Orientation,
25-
reorderLongPressEnabledProperty,
26-
reorderingEnabledProperty,
27-
reverseLayoutProperty,
28-
scrollBarIndicatorVisibleProperty
29-
} from '.';
20+
import { CollectionViewItemEventData, Orientation, reorderLongPressEnabledProperty, reorderingEnabledProperty, reverseLayoutProperty, scrollBarIndicatorVisibleProperty } from '.';
3021
import { CLog, CLogTypes, CollectionViewBase, ListViewViewTypes, isScrollEnabledProperty, orientationProperty } from './index-common';
3122

3223
export * from './index-common';
@@ -152,11 +143,9 @@ export class CollectionView extends CollectionViewBase {
152143

153144
private currentSpanCount = 1;
154145

155-
// used to store viewHolder and make sure they are not garbaged
156-
private _viewHolders = new Array<CollectionViewCellHolder>();
157-
146+
// used to store viewHolder and thus their corresponding Views
158147
// used to "destroy" cells when possible
159-
private _viewHolderChildren = new Array();
148+
private _viewHolders = new Set<WeakRef<CollectionViewCellHolder>>();
160149

161150
private _scrollOrLoadMoreChangeCount = 0;
162151
private _nScrollListener: com.nativescript.collectionview.OnScrollListener.Listener;
@@ -274,16 +263,7 @@ export class CollectionView extends CollectionViewBase {
274263

275264
_getSpanSize: (item, index) => number;
276265
public getViewForItemAtIndex(index: number): View {
277-
let result: View;
278-
this._viewHolders.some(function (cellItemView, key) {
279-
if (cellItemView && cellItemView.getAdapterPosition() === index) {
280-
result = cellItemView.view;
281-
return true;
282-
}
283-
return false;
284-
});
285-
286-
return result;
266+
return this.enumerateViewHolders<View>((v) => (v.getAdapterPosition() === index ? v.view : undefined));
287267
}
288268
//@ts-ignore
289269
set spanSize(inter: (item, index) => number) {
@@ -538,16 +518,23 @@ export class CollectionView extends CollectionViewBase {
538518
this.nativeViewProtected.setVerticalScrollBarEnabled(value);
539519
}
540520
}
521+
private enumerateViewHolders<T = any>(cb: (v: CollectionViewCellHolder) => T) {
522+
let result: T, v: CollectionViewCellHolder;
523+
for (let it = this._viewHolders.values(), cellItemView: WeakRef<CollectionViewCellHolder> = null; (cellItemView = it.next().value); ) {
524+
v = cellItemView?.get();
525+
if (v) {
526+
result = cb(v);
527+
if (result) {
528+
return result;
529+
}
530+
}
531+
}
532+
return result;
533+
}
541534
public startDragging(index: number) {
542535
if (this.reorderEnabled && this._itemTouchHelper) {
543-
let viewHolder: CollectionViewCellHolder;
544-
this._viewHolders.some((v) => {
545-
if (v.getAdapterPosition() === index) {
546-
viewHolder = v;
547-
return true;
548-
}
549-
return false;
550-
});
536+
// let viewHolder: CollectionViewCellHolder;
537+
const viewHolder = this.enumerateViewHolders<CollectionViewCellHolder>((v) => (v.getAdapterPosition() === index ? v : undefined));
551538
if (viewHolder) {
552539
this.startViewHolderDragging(index, viewHolder);
553540
}
@@ -637,11 +624,6 @@ export class CollectionView extends CollectionViewBase {
637624
super.onItemTemplatesChanged(oldValue, newValue); // TODO: update current template with the new one
638625
this.refresh();
639626
}
640-
// public eachChildView(callback: (child: View) => boolean): void {
641-
// this._realizedItems.forEach((view, key) => {
642-
// callback(view);
643-
// });
644-
// }
645627

646628
private setOnLayoutChangeListener() {
647629
if (this.nativeViewProtected) {
@@ -772,13 +754,16 @@ export class CollectionView extends CollectionViewBase {
772754

773755
eachChild(callback: (child: ViewBase) => boolean) {
774756
// used for css updates (like theme change)
775-
this._viewHolders.forEach(({ view }, nativeView) => {
776-
if (view.parent instanceof CollectionView) {
777-
callback(view);
778-
} else {
779-
// in some cases (like item is unloaded from another place (like angular) view.parent becomes undefined)
780-
if (view.parent) {
781-
callback(view.parent);
757+
this.enumerateViewHolders((v) => {
758+
const view = v.view;
759+
if (view) {
760+
if (view.parent instanceof CollectionView) {
761+
callback(view);
762+
} else {
763+
// in some cases (like item is unloaded from another place (like angular) view.parent becomes undefined)
764+
if (view.parent) {
765+
callback(view.parent);
766+
}
782767
}
783768
}
784769
});
@@ -788,8 +773,9 @@ export class CollectionView extends CollectionViewBase {
788773
if (!view) {
789774
return;
790775
}
791-
const ids = this._viewHolders
792-
.map((s) => s['position'])
776+
const ids = Array.from(this._viewHolders)
777+
.filter((s) => s.get())
778+
.map((s) => s.get()['position'])
793779
.filter((s) => s !== null)
794780
.sort((a, b) => a - b);
795781
this._listViewAdapter.notifyItemRangeChanged(ids[0], ids[ids.length - 1] - ids[0] + 1);
@@ -956,13 +942,11 @@ export class CollectionView extends CollectionViewBase {
956942
}
957943

958944
disposeViewHolderViews() {
959-
this._viewHolders.forEach((v) => {
945+
this.enumerateViewHolders((v) => {
946+
this._removeViewCore(v.view);
960947
v.view = null;
961948
v.clickListener = null;
962949
});
963-
this._viewHolders = new Array();
964-
this._viewHolderChildren.forEach((v) => this._removeViewCore(v));
965-
this._viewHolderChildren = new Array();
966950
}
967951
getKeyByValue(viewType: number) {
968952
return this.templateStringTypeNumber.get(viewType);
@@ -978,7 +962,7 @@ export class CollectionView extends CollectionViewBase {
978962
parentView.id = 'collectionViewHolder';
979963
view = parentView;
980964
}
981-
this._viewHolderChildren.push(view);
965+
// this._viewHolderChildren.push(new WeakRef(view));
982966
this._addView(view);
983967
if (!CollectionViewCellHolder) {
984968
CollectionViewCellHolder = com.nativescript.collectionview.CollectionViewCellHolder as any;
@@ -1007,7 +991,7 @@ export class CollectionView extends CollectionViewBase {
1007991
if (isNonSync) {
1008992
holder['defaultItemView'] = true;
1009993
}
1010-
this._viewHolders.push(holder);
994+
this._viewHolders.add(new WeakRef(holder));
1011995

1012996
return holder;
1013997
}

0 commit comments

Comments
 (0)