Skip to content

Commit 18fe939

Browse files
Hristo HristovHristo Hristov
authored andcommitted
Fix memory leak in edit-text.android
Fix fromObjectRecursive to doesn't override source object
1 parent 82f081d commit 18fe939

File tree

5 files changed

+61
-35
lines changed

5 files changed

+61
-35
lines changed

tests/app/data/observable-tests.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,4 +558,11 @@ export function test_get_set_on_observables_fromObject_with_property_in_json() {
558558
const value2 = (<any>vm).p;
559559
TKUnit.assertEqual(value1, array);
560560
TKUnit.assertEqual(value2, array);
561+
}
562+
563+
export function test_fromObjectRecursive_does_not_override_source_object_property() {
564+
const myObj = {};
565+
const source = { name: "a", value: myObj };
566+
const observable = fromObjectRecursive(source);
567+
TKUnit.assertEqual(source.value, myObj);
561568
}

tests/app/testRunner.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,11 @@ function showReportPage(finalMessage: string) {
348348
page.content = stack;
349349
messageContainer.focus();
350350
page.style.fontSize = 11;
351-
if (page.android) {
352-
setTimeout(() => {
353-
messageContainer.dismissSoftInput();
354-
(<android.view.View>messageContainer.nativeViewProtected).scrollTo(0, 0);
355-
}, 500);
351+
if (platform.isAndroid) {
352+
page.on('navigatedTo', () => {
353+
messageContainer.focus();
354+
setTimeout(() => messageContainer.dismissSoftInput());
355+
});
356356
}
357357

358358
return page;

tns-core-modules/data/observable/observable.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ class ObservableFromObject extends Observable {
188188
public get(name: string): any {
189189
return this._map[name];
190190
}
191-
191+
192192
public set(name: string, value: any) {
193193
const currentValue = this._map[name];
194194
if (currentValue === value) {
@@ -218,13 +218,17 @@ function addPropertiesFromObject(observable: ObservableFromObject, source: any,
218218
let isRecursive = recursive;
219219
for (let prop in source) {
220220
if (source.hasOwnProperty(prop)) {
221-
if (isRecursive) {
222-
if (!Array.isArray(source[prop]) && source[prop] && typeof source[prop] === 'object' && !(source[prop] instanceof Observable)) {
223-
source[prop] = fromObjectRecursive(source[prop]);
224-
}
221+
let value = source[prop];
222+
if (isRecursive
223+
&& !Array.isArray(value)
224+
&& value
225+
&& typeof value === 'object'
226+
&& !(value instanceof Observable)) {
227+
value = fromObjectRecursive(value);
225228
}
229+
226230
defineNewProperty(observable, prop);
227-
observable.set(prop, source[prop]);
231+
observable.set(prop, value);
228232
}
229233
}
230234
}

tns-core-modules/ui/core/view-base/view-base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,10 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
251251
this._style = new Style(this);
252252
}
253253

254+
// Used in Angular.
254255
get parentNode() {
255256
return this._templateParent || this.parent;
256257
}
257-
258258
set parentNode(node: ViewBase) {
259259
this._templateParent = node;
260260
}

tns-core-modules/ui/editable-text-base/editable-text-base.android.ts

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { ad } from "../../utils/utils";
1010
export * from "./editable-text-base-common";
1111

1212
//https://github.com/NativeScript/NativeScript/issues/2942
13-
let dismissKeyboardTimeoutId: any;
13+
export let dismissKeyboardTimeoutId: NodeJS.Timer;
14+
export let dismissKeyboardOwner: WeakRef<EditableTextBase>;
1415

1516
interface EditTextListeners extends android.text.TextWatcher, android.view.View.OnFocusChangeListener, android.widget.TextView.OnEditorActionListener {
1617
}
@@ -22,6 +23,30 @@ interface EditTextListenersClass {
2223

2324
let EditTextListeners: EditTextListenersClass;
2425

26+
function clearDismissTimer(): void {
27+
dismissKeyboardOwner = null;
28+
if (dismissKeyboardTimeoutId) {
29+
clearTimeout(dismissKeyboardTimeoutId);
30+
dismissKeyboardTimeoutId = null;
31+
}
32+
}
33+
34+
function dismissSoftInput(owner: EditableTextBase): void {
35+
clearDismissTimer();
36+
if (!dismissKeyboardTimeoutId) {
37+
dismissKeyboardTimeoutId = setTimeout(() => {
38+
const owner = dismissKeyboardOwner && dismissKeyboardOwner.get();
39+
const activity = (owner && owner._context) as android.app.Activity;
40+
const nativeView = owner && owner.nativeViewProtected;
41+
dismissKeyboardTimeoutId = null;
42+
dismissKeyboardOwner = null;
43+
const focused = activity && activity.getCurrentFocus();
44+
if (!focused || !(focused instanceof android.widget.EditText)) {
45+
ad.dismissSoftInput(nativeView);
46+
}
47+
}, 10);
48+
}
49+
}
2550
function initializeEditTextListeners(): void {
2651
if (EditTextListeners) {
2752
return;
@@ -71,7 +96,7 @@ function initializeEditTextListeners(): void {
7196
}
7297

7398
if (hasFocus) {
74-
owner.clearDismissTimer();
99+
clearDismissTimer();
75100
owner.notify({ eventName: EditableTextBase.focusEvent, object: owner });
76101
} else {
77102
if (owner._dirtyTextAccumulator || owner._dirtyTextAccumulator === "") {
@@ -80,7 +105,7 @@ function initializeEditTextListeners(): void {
80105
}
81106

82107
owner.notify({ eventName: EditableTextBase.blurEvent, object: owner });
83-
owner.dismissSoftInput();
108+
dismissSoftInput(owner);
84109
}
85110
}
86111

@@ -129,7 +154,6 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
129154
private _inputType: number;
130155

131156
public _changeFromCode: boolean;
132-
public _dismissId: NodeJS.Timer;
133157

134158
public abstract _configureEditText(editText: android.widget.EditText): void;
135159

@@ -168,35 +192,26 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
168192
this.nativeViewProtected.setInputType(this._inputType);
169193
}
170194

195+
public onUnloaded() {
196+
this.dismissSoftInput();
197+
super.onUnloaded();
198+
}
199+
171200
public dismissSoftInput() {
172201
const nativeView = this.nativeViewProtected;
173202
if (!nativeView) {
174203
return;
175204
}
176205

177-
const activity = this._context as android.app.Activity;
178-
if (!this._dismissId) {
179-
this._dismissId = setTimeout(() => {
180-
this._dismissId = null;
181-
const focused = activity.getCurrentFocus();
182-
if (!focused
183-
|| focused === nativeView
184-
|| !(focused instanceof android.widget.EditText)) {
185-
ad.dismissSoftInput(nativeView);
186-
}
187-
}, 100);
188-
}
206+
ad.dismissSoftInput(nativeView);
189207
}
190208

191-
public clearDismissTimer(): void {
192-
if (this._dismissId) {
193-
clearTimeout(this._dismissId);
194-
this._dismissId = null;
209+
public focus(): boolean {
210+
const nativeView = this.nativeViewProtected;
211+
if (!nativeView) {
212+
return;
195213
}
196-
}
197214

198-
public focus(): boolean {
199-
this.clearDismissTimer();
200215
const result = super.focus();
201216
if (result) {
202217
ad.showSoftInput(this.nativeViewProtected);

0 commit comments

Comments
 (0)