mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
fix(android): memory leak with EditableTextBase (#10052)
This commit is contained in:
@ -27,12 +27,11 @@ function clearDismissTimer(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dismissSoftInput(_owner: WeakRef<EditableTextBase>): void {
|
function dismissSoftInput(view: EditableTextBase): void {
|
||||||
clearDismissTimer();
|
clearDismissTimer();
|
||||||
if (!dismissKeyboardTimeoutId) {
|
if (!dismissKeyboardTimeoutId) {
|
||||||
dismissKeyboardTimeoutId = setTimeout(() => {
|
dismissKeyboardTimeoutId = setTimeout(() => {
|
||||||
const owner = _owner && _owner.get();
|
const activity = view._context as androidx.appcompat.app.AppCompatActivity;
|
||||||
const activity = owner?._context as androidx.appcompat.app.AppCompatActivity;
|
|
||||||
dismissKeyboardTimeoutId = null;
|
dismissKeyboardTimeoutId = null;
|
||||||
const focused = activity && activity.getCurrentFocus();
|
const focused = activity && activity.getCurrentFocus();
|
||||||
if (focused && !(focused instanceof android.widget.EditText)) {
|
if (focused && !(focused instanceof android.widget.EditText)) {
|
||||||
@ -61,81 +60,23 @@ function initializeEditTextListeners(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public beforeTextChanged(text: string, start: number, count: number, after: number): void {
|
public beforeTextChanged(text: string, start: number, count: number, after: number): void {
|
||||||
//
|
this.owner?.get()?.beforeTextChanged(text, start, count, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onTextChanged(text: string, start: number, before: number, count: number): void {
|
public onTextChanged(text: string, start: number, before: number, count: number): void {
|
||||||
// const owner = this.owner;
|
this.owner?.get()?.onTextChanged(text, start, before, count);
|
||||||
// let selectionStart = owner.android.getSelectionStart();
|
|
||||||
// owner.android.removeTextChangedListener(owner._editTextListeners);
|
|
||||||
// owner.android.addTextChangedListener(owner._editTextListeners);
|
|
||||||
// owner.android.setSelection(selectionStart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public afterTextChanged(editable: android.text.Editable): void {
|
public afterTextChanged(editable: android.text.Editable): void {
|
||||||
const owner = this.owner && this.owner.get();
|
this.owner?.get()?.afterTextChanged(editable);
|
||||||
if (!owner || owner._changeFromCode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (owner.updateTextTrigger) {
|
|
||||||
case 'focusLost':
|
|
||||||
owner._dirtyTextAccumulator = editable.toString();
|
|
||||||
break;
|
|
||||||
case 'textChanged':
|
|
||||||
textProperty.nativeValueChange(owner, editable.toString());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error('Invalid updateTextTrigger: ' + owner.updateTextTrigger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onFocusChange(view: android.view.View, hasFocus: boolean): void {
|
public onFocusChange(view: android.view.View, hasFocus: boolean): void {
|
||||||
const owner = this.owner && this.owner.get();
|
this.owner?.get()?.onFocusChange(view, hasFocus);
|
||||||
if (!owner) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasFocus) {
|
|
||||||
clearDismissTimer();
|
|
||||||
owner.notify({
|
|
||||||
eventName: EditableTextBase.focusEvent,
|
|
||||||
object: owner,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (owner._dirtyTextAccumulator || owner._dirtyTextAccumulator === '') {
|
|
||||||
textProperty.nativeValueChange(owner, owner._dirtyTextAccumulator);
|
|
||||||
owner._dirtyTextAccumulator = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
owner.notify({
|
|
||||||
eventName: EditableTextBase.blurEvent,
|
|
||||||
object: owner,
|
|
||||||
});
|
|
||||||
dismissSoftInput(this.owner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onEditorAction(textView: android.widget.TextView, actionId: number, event: android.view.KeyEvent): boolean {
|
public onEditorAction(textView: android.widget.TextView, actionId: number, event: android.view.KeyEvent): boolean {
|
||||||
const owner = this.owner && this.owner.get();
|
return this.owner?.get()?.onEditorAction(textView, actionId, event) || false;
|
||||||
if (!owner) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_DONE || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_UNSPECIFIED || (event && event.getKeyCode() === android.view.KeyEvent.KEYCODE_ENTER)) {
|
|
||||||
// If it is TextField, close the keyboard. If it is TextView, do not close it since the TextView is multiline
|
|
||||||
// https://github.com/NativeScript/NativeScript/issues/3111
|
|
||||||
if (textView.getMaxLines() === 1) {
|
|
||||||
owner.dismissSoftInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
owner._onReturnPress();
|
|
||||||
} else if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_NEXT || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS) {
|
|
||||||
// do not close keyboard for ACTION_NEXT or ACTION_PREVIOUS
|
|
||||||
owner._onReturnPress();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +119,12 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public disposeNativeView(): void {
|
public disposeNativeView(): void {
|
||||||
(<any>this.nativeTextViewProtected).listener.owner = null;
|
const editText = this.nativeTextViewProtected;
|
||||||
|
editText.removeTextChangedListener((<any>editText).listener);
|
||||||
|
editText.setOnFocusChangeListener(null);
|
||||||
|
editText.setOnEditorActionListener(null);
|
||||||
|
(<any>editText).listener.owner = null;
|
||||||
|
(<any>editText).listener = null;
|
||||||
this._keyListenerCache = null;
|
this._keyListenerCache = null;
|
||||||
super.disposeNativeView();
|
super.disposeNativeView();
|
||||||
}
|
}
|
||||||
@ -531,4 +477,72 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public beforeTextChanged(text: string, start: number, count: number, after: number): void {
|
||||||
|
// called by android.text.TextWatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
public onTextChanged(text: string, start: number, before: number, count: number): void {
|
||||||
|
// called by android.text.TextWatcher
|
||||||
|
// const owner = this.owner;
|
||||||
|
// let selectionStart = owner.android.getSelectionStart();
|
||||||
|
// owner.android.removeTextChangedListener(owner._editTextListeners);
|
||||||
|
// owner.android.addTextChangedListener(owner._editTextListeners);
|
||||||
|
// owner.android.setSelection(selectionStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public afterTextChanged(editable: android.text.Editable): void {
|
||||||
|
// called by android.text.TextWatcher
|
||||||
|
if (this._changeFromCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.updateTextTrigger) {
|
||||||
|
case 'focusLost':
|
||||||
|
this._dirtyTextAccumulator = editable.toString();
|
||||||
|
break;
|
||||||
|
case 'textChanged':
|
||||||
|
textProperty.nativeValueChange(this, editable.toString());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid updateTextTrigger: ' + this.updateTextTrigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onFocusChange(view: android.view.View, hasFocus: boolean): void {
|
||||||
|
if (hasFocus) {
|
||||||
|
clearDismissTimer();
|
||||||
|
this.notify({
|
||||||
|
eventName: EditableTextBase.focusEvent,
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (this._dirtyTextAccumulator || this._dirtyTextAccumulator === '') {
|
||||||
|
textProperty.nativeValueChange(this, this._dirtyTextAccumulator);
|
||||||
|
this._dirtyTextAccumulator = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notify({
|
||||||
|
eventName: EditableTextBase.blurEvent,
|
||||||
|
});
|
||||||
|
dismissSoftInput(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEditorAction(textView: android.widget.TextView, actionId: number, event: android.view.KeyEvent): boolean {
|
||||||
|
if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_DONE || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_UNSPECIFIED || (event && event.getKeyCode() === android.view.KeyEvent.KEYCODE_ENTER)) {
|
||||||
|
// If it is TextField, close the keyboard. If it is TextView, do not close it since the TextView is multiline
|
||||||
|
// https://github.com/NativeScript/NativeScript/issues/3111
|
||||||
|
if (textView.getMaxLines() === 1) {
|
||||||
|
this.dismissSoftInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onReturnPress();
|
||||||
|
} else if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_NEXT || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS) {
|
||||||
|
// do not close keyboard for ACTION_NEXT or ACTION_PREVIOUS
|
||||||
|
this._onReturnPress();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user