TextWatcher springt nicht an

kurztipp

Aktives Mitglied
Hallo,

ich kämpfe nach wie vor mit dem ListView, das durch einen SimpleCursorAdapter gefüllt wird. Jetzt geht es darum, Daten aus einem EditText bei/nach Benutzereingabe abzurufen. Das wollte ich über ein TextWatcher machen.

Wenn in das EditText etwas geschrieben wird, sollen sich die Daten in einem TextView ändern (simple Multiplikation mit vorgegebenem Wert). Das funktioniert mit dem TextWatcher aber nur halb und unzufriedenstellend -- mit anderen Worten: gar nicht.

Java:
private final TextWatcher mTextWatcher = new TextWatcher() {

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

		log(s);
	}

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

	@Override
	public void afterTextChanged(Editable s) {
		log("afterTextChanged");
	}
};

//...

mAdapter.changeCursor(cursor);

setListAdapter(mAdapter);

for (int i = 0; i < mAdapter.getCount(); i++) {
	EditText edit = (EditText) mAdapter.getView(i, null, getListView())
			.findViewById(R.id.F_DI_ET_amount);

	edit.addTextChangedListener(mTextWatcher);
	edit.getEditableText().insert(0, "50"); // funktioniert
}

EditText edit = ((EditText) mAdapter.getView(0, null, getListView())
		.findViewById(R.id.F_DI_ET_amount));
edit.getEditableText().insert(0, "100"); //funktioniert nicht

Ich erhalte in der for-Schleife das EditText, das in der jeweiligen Reihe ist. Der erste insert() Aufruf funktioniert und wird an den Listener übergeben. Der Zweite, warum auch immer, funktioniert nicht. Ebensowenig werden Benutzereingaben an den Listener weitergegeben.

Es scheint, als ob der TextWatcher von den EditTexts direkt nach der for-Schleife wieder gelöscht wird.

Wo liegt der Fehler?
 
Zuletzt bearbeitet:
Das der TextWatcher gelöscht wird, glaube ich nicht. Was passiert denn, wenn du als Person - als nicht über den Code - etwas eingibst?

BTW: Ich finde den TextWatcher in Android echt s******e. Man muss teilweise Umstände machen, wenn er mal temporär nicht "zuhören" soll. Ich verstehe auch nicht, dass es ausgerechnet hier möglich ist, mehr als einen Listener anzuhängen... Wozu?
 
Hallo,

Das der TextWatcher gelöscht wird, glaube ich nicht. Was passiert denn, wenn du als Person - als nicht über den Code - etwas eingibst?
Gar nichts passiert. Ich kann etwas eingeben, das steht dann auch im EditText, aber das wars auch schon. Die Listener machen gar nichts, weil sie offensichtlich nicht angesprochen werden.

Gruß
 
Ich denke, es werden einfach die "falschen" angesprochen. Mache es anders und hänge die Listener bereits im Adapter an die EditText-Felder. Also in der getView- (oder bindView-) Methode (je nachdem, was du nutzt). Teste mit einer generischen Implementierung mal, ob es klappt (was ich glaube!) und dann mach dir Gedanken, wie du die Daten aus den Adapter raus bekommst... War das in etwa verständlich?
 
Hallo,

Ich denke, es werden einfach die "falschen" angesprochen.
Ja, es wurden scheinbar die falschen angesprochen, auch wenn ich absolut nich navollziehen kann, welche und wieso.

Mache es anders und hänge die Listener bereits im Adapter an die EditText-Felder. Also in der getView- (oder bindView-) Methode (je nachdem, was du nutzt).
Das hat weitergeholfen. Ich habe mich von dem Ansatz verabschiedet, keinen eigenen Adapter zu implementieren und bin dem Ansatz dieses Tutorials gefolgt und habe einen privaten Adapter implementiert, der nur
Code:
getView()
überschreibt und den TextWatcher implementiert und setzt:
Java:
private class CustomCursorAdapter extends SimpleCursorAdapter {

	Context mContext;

	public CustomCursorAdapter(Context context, int layout, Cursor c,
			String[] from, int[] to, int flags) {
		super(context, layout, c, from, to, flags);

		mContext = context;
	}

	@Override
	public View getView(int position, View view, ViewGroup parent) {
		EditText edit;

		view = super.getView(position, view, parent);
		edit = (EditText) view.findViewById(R.id.edit);
		edit.addTextChangedListener(new MyTextWatcher(view));
		edit.setTag(mObjectList.get(position));

		Cursor cursor = super.getCursor();
		cursor.moveToPosition(position);
		bindView(view, mContext, cursor);

		return view;

	}

	private class MyTextWatcher implements TextWatcher {

		private View mView;

		private MyTextWatcher(View view) {
			mView = view;
		}

		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {
			// do nothing
		}

		public void onTextChanged(CharSequence s, int start, int before,
				int count) {
			// do nothing
		}

		public void afterTextChanged(Editable s) {

			EditText edit = (EditText) mView
					.findViewById(R.id.edit);
			Object object = (Object) edit.getTag();

			object.doSomething(s.toString());
			mAdapter.notifyDataSetChanged();
			log(edit.requestFocus());
		}
	}
}

Das funktioniert so weit auch alles wunderbar! Das einzige Problem, das ich habe, ist, dass
Code:
notifiyDataSetChanged()
dem EditText den Fokus enzieht und man daher immer nur eine Ziffer eingeben kann. Das ist äußerst unkomfortabel, denn das bedeutet: Zahl eingeben -> ListView aktualisiert sich -> Fokus weg -> in EditText klicken -> nächste Zahl usw, also jedes mal manuell wieder den Fokus herstellen.
Leider verschafft
Code:
edit.requerstFocus()
keine Abhilfe, obwohl es
Code:
true
zurückgibt.

Gruß
 
Dann mach doch diese Operation erst, wenn Enter oder so gedrückt wurde. [c]notifyDataSetChanged[/c] macht . glaube ich - auch einen relativ teuren Refresh auf der ganzen Liste. Bei kleinen Listen ist das ok, bei großen aber eher Overkill!

Oder bau irgendeinen Timer ein: Wenn x Sekunden nichts gemacht wurde, dann führe die Operationen durch, ansonsten setze den Timmer wieder zurück.

Mir stellt sich gerade noch die Frage: Geht es auch ohne den [c]notifyDataSetChanged[/c]? Brauchst du den um irgend etwas in der Liste anhand dieser Daten anzupassen? Wenn ja, dann verstehe ich es durchaus...
 
Ach so noch ein Nachtrag zu vorangegangenen Post: Ich denke der Grund, warum dein erster Ansatz nicht geklappt hat, ist am Ende recht einfach: Du wirst im getView immer einen neuen View inflaten und zurückgeben! Warum mir das nicht schon neulich eingefallen ist! Eine Lösung wäre eine Map von Item auf View innerhalb der Implementierung des Adapters gewesen.
 
Hallo,

Dann mach doch diese Operation erst, wenn Enter oder so gedrückt wurde. [c]notifyDataSetChanged[/c] macht . glaube ich - auch einen relativ teuren Refresh auf der ganzen Liste. Bei kleinen Listen ist das ok, bei großen aber eher Overkill! [...]

Mir stellt sich gerade noch die Frage: Geht es auch ohne den [c]notifyDataSetChanged[/c]? Brauchst du den um irgend etwas in der Liste anhand dieser Daten anzupassen? Wenn ja, dann verstehe ich es durchaus...
Die Aktualisierung brauche ich, aber bisher nur innerhalb des Datensets. Habs daher anders gelöst. Hatte mit dem Aufruf von [c]notifyDataSetChanged[/c] einen falschen bzw zu komplizierten Ansatz gewählt.
Ich habe ja innerhalb der TextWatcher Implementierung eine Referenz die View, die das Datenset enthält. Also hab ich einfach die korrespondierenden Views (
Code:
findViewById()
) gleich mit aktualisiert -- [c]notifyDataSetChanged[/c] entfällt (wird auch in dem o.g. Link so gehandhabt).

Dass eine gänzlich neue Liste erzeugt wird, habe ich mir auch bereits gedacht. Dann wäre die Referenz auf EditText veraltet und der Focus request zwar erfolgreich, aber nutzlos, so wies auch tatsächlich ist.

Oder bau irgendeinen Timer ein: Wenn x Sekunden nichts gemacht wurde, dann führe die Operationen durch, ansonsten setze den Timmer wieder zurück.
Guter Ansatz, ist evtl für anderes oder andere Interessant.

Gruß
 
Zuletzt bearbeitet:
Hallo,

ja habe ich. Nachdem ich mir den Sourcecode der getView Methode beim Implementieren genauer angeschaut habe, ist mir das dann im Nachhinein auch aufgefallen, aber auf das Problem hab ichs vor Deinem Post noch nicht bezogen gehabt 😀
Ich finde das Verhalten bzw die Namensgebung ein wenig irreführend, da es (zumindest mir) suggeriert hat, man bekommt dadurch Zugriff auf ein Datenset des Adapters.

Gruß
 

Zurück
Oben