Merge pull request #2263 from NativeScript/nnikoilov/ListViewUsedInAModalDialogCrash

Fixed crash when ListView is used in a modal dialog (Android).
This commit is contained in:
Nedyalko Nikolov
2016-06-08 18:43:08 +03:00
2 changed files with 42 additions and 6 deletions

View File

@ -558,6 +558,38 @@ export class ListViewTest extends testModule.UITest<listViewModule.ListView> {
} }
} }
public test_RemovingChildViewsBeforeListView() {
var listView = this.testView;
var converterCalledCounter = 0;
var testConverter = function (value) {
converterCalledCounter++;
return value;
}
app.resources["testConverter"] = testConverter;
var listViewModel = new observable.Observable();
listViewModel.set("items", [1, 2, 3]);
listView.bindingContext = listViewModel;
listView.bind({ sourceProperty: "items", targetProperty: "items" });
listView.itemTemplate = "<StackLayout><Label id=\"testLabel\" text=\"{{ $value, $value | testConverter }}\" /></StackLayout>";
this.waitUntilListViewReady();
if (platform.isAndroid) {
// simulates Angular way of removing views
(<any>listView)._realizedItems.forEach((view, nativeView, map) => {
console.log("view: " + view);
listView._removeView(view);
});
this.tearDown();
// should not crash
TKUnit.assertTrue(true);
}
}
public test_no_memory_leak_when_items_is_regular_array() { public test_no_memory_leak_when_items_is_regular_array() {
let weakRef = new WeakRef<listViewModule.ListView>(this.testView); let weakRef = new WeakRef<listViewModule.ListView>(this.testView);
weakRef.get().items = FEW_ITEMS; weakRef.get().items = FEW_ITEMS;

View File

@ -108,8 +108,11 @@ export class ListView extends common.ListView {
callback(view); callback(view);
} }
else { else {
// in some cases (like item is unloaded from another place (like angular) view.parent becomes undefined)
if (view.parent) {
callback(view.parent); callback(view.parent);
} }
}
}); });
} }
@ -124,12 +127,13 @@ export class ListView extends common.ListView {
private clearRealizedCells(): void { private clearRealizedCells(): void {
// clear the cache // clear the cache
this._realizedItems.forEach((view, nativeView, map) => { this._realizedItems.forEach((view, nativeView, map) => {
if (view.parent) {
// This is to clear the StackLayout that is used to wrap non LayoutBase & ProxyViewContainer instances. // This is to clear the StackLayout that is used to wrap non LayoutBase & ProxyViewContainer instances.
if (!(view.parent instanceof ListView)) { if (!(view.parent instanceof ListView)) {
this._removeView(view.parent); this._removeView(view.parent);
} }
view.parent._removeView(view); view.parent._removeView(view);
}
}); });
this._realizedItems.clear(); this._realizedItems.clear();