Domanda

TextWatcher works fine until my activity is destroyed and before restoring from old saved bundle. But when I restore from saved bundle onTextChanged() is called for both of my EditTexts. This happens even if I don't restore their values (don't call setText()). Note that user is not interacting in any way.

Code :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.create_trip);
    Log.d(TAG, "onCreate");

    fromLocation = (EditText) findViewById(R.id.from_location);
    toLocation = (EditText) findViewById(R.id.to_location);

    // Set EditTexts listeners
    setFromLocationEditTextListeres();
    setToLocationEditTextListeres();

    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {

        Log.d(TAG, "Restoring state from saved bundle");
        ...

    } else {
        Log.e(TAG, "Setting default values");
        ... 
    }
}


// Set listener for fromLocation EditText
private void setFromLocationEditTextListeres() {

    fromLocation.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {

                Log.d(TAG, "fromLocation gained focus.");

            }
        }
    });

    fromLocation.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable s) {
            Log.e(TAG, "Fromlocation after.");
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {

            if (fromLocation == null) {
                Log.d(TAG, "fromLocation is null................");
            }

            if (count != before) {
                editTextValueChanged(fromLocation);
            }
        }
    });

    fromLocation.setOnKeyListener(new View.OnKeyListener() {

        public boolean onKey(View v, int keyCode, KeyEvent event) {

            // If user pressed enter
            if (keyCode == KeyEvent.KEYCODE_ENTER) {

            }

            // If pressed other than enter key then let others handle the
            // event
            return false;
        }
    });
}

// Set listener for toLocation EditText
private void setToLocationEditTextListeres() {

    toLocation.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {

                Log.d(TAG, "toLocation gained focus.");
            }
        }
    });

    toLocation.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable s) {
            Log.e(TAG, "Tolocation after.");
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {

            if (count != before) {
                editTextValueChanged(toLocation);
            }
        }
    });

    toLocation.setOnKeyListener(new View.OnKeyListener() {

        public boolean onKey(View v, int keyCode, KeyEvent event) {

            // If user pressed enter
            if (keyCode == KeyEvent.KEYCODE_ENTER) {

            }

            // If pressed other than enter key then let others handle the
            // event
            return false;
        }
    });

}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {

    Log.e(TAG, "onSaveInstanceState called.");

    // Save activity state
    savedInstanceState.putCharSequence(FROM_LOCATION_TEXT,
            fromLocation.getText());
    savedInstanceState.putCharSequence(TO_LOCATION_TEXT,
            toLocation.getText());
    super.onSaveInstanceState(savedInstanceState);
}
È stato utile?

Soluzione

After headache of few hours the reason of issue comes out to be my following code :

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {

    Log.e(TAG, "onSaveInstanceState called.");

    // Save activity state
    savedInstanceState.putCharSequence(FROM_LOCATION_TEXT,
            fromLocation.getText());
    savedInstanceState.putCharSequence(TO_LOCATION_TEXT,
            toLocation.getText());
    super.onSaveInstanceState(savedInstanceState);
}

What happens is android itself stores my EditText's state (if id attribute is specified in layout file) and when activity is restored using saved bundle it restores EditText's value by calling myEditText.setText(). This was triggering call to text changed listeners.

Solution is removing lines from above code which saves EditText's text. Do not save EditText or similar View's state explicitly. Let android do it for you.

Altri suggerimenti

The answer to this is that you first @Override the onTextChanged() in fromLocation.addTextChangedListener and then you @Override it once more inside of toLocation.addTextChangedListener. Then in the onCreate inside of if (savedInstanceState != null) { you have:

 fromLocation.setText(savedInstanceState
 .getCharSequence(FROM_LOCATION_TEXT));
 toLocation.setText(savedInstanceState
 .getCharSequence(TO_LOCATION_TEXT)); 

Which triggers both mentioned addTextChangedListeners.

EDIT (following the update of the question):

In the onCreate you call this, before any if statements:

// Set EditTexts listeners
setFromLocationEditTextListeres();
setToLocationEditTextListeres();

Then you have:

@Override public void onSaveInstanceState(Bundle savedInstanceState) {

Log.e(TAG, "onSaveInstanceState called.");

// Save activity state
savedInstanceState.putCharSequence(FROM_LOCATION_TEXT,
        fromLocation.getText());
savedInstanceState.putCharSequence(TO_LOCATION_TEXT,
        toLocation.getText());
super.onSaveInstanceState(savedInstanceState);

}

So, you're restoring the text in the EditTexts from here above, then in the onCreate you set the listeners - thus setting the text on the EditTexts triggers the onTextChanged for bothe the EditTexts. Afterwards in the onCreate method you have:

if (savedInstanceState != null) {

    Log.d(TAG, "Restoring state from saved bundle");
    // Restore value of members from saved state

    .../*Intentionnaly missed part*/
     fromLocation.setText(savedInstanceState
     .getCharSequence(FROM_LOCATION_TEXT)); <- Here you set the text again and trigger the `onTextChanged` 
    .../*Intentionnaly missed part*/
     toLocation.setText(savedInstanceState
     .getCharSequence(TO_LOCATION_TEXT)); <- Here you set the text again and trigger the `onTextChanged

} else {
    Log.e(TAG, "Setting default values");
    .../*Intentionnaly missed part*/
    fromLocation.setText("Hello");<- Here you set the text again and trigger the `onTextChanged
}

I think that the described behaviour (e.g. "TextWatcher works fine until my activity is destroyed and before restoring from old saved bundle. But when I restore from saved bundle onTextChanged() is called for both of my EditTexts. This happens even if I don't restore their values (don't call setText()). Note that user is not interacting in any way.") happens only in the case of fromLocation (EditText) and not in both the cases (e.g. fromLocation and toLocation).

To finish this - you have also lots and lots of flags, which I don't even know what are they used for. To underline also the function editTextGainedFocus(EditText) which is not described here.

Cheers.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top