AutoCompleteTextView wird von CursorLoader unterstützt
Also ich habe Probleme bei der Verlängerung der MultiAutoCompleteTextView
und sichern es mit einem CursorLoader
während Sie gleichzeitig mithilfe einer benutzerdefinierten Tokenizer
. Die Frage erhebt sich insbesondere mit der mAdapter.setCursorToStringConverter();
nennen. Die convertToString()
Methode, die ein Cursor, der als argument eine gültige und unverschlossenen cursor auf den ersten Aufruf dieser Methode. Jedoch nachfolgende Aufrufe zu einer null-cursor oder cursor geschlossen. Ich vermute, das hat etwas damit zu tun, wie die LoaderManager
verwaltet die CursorLoader
.
Wenn ich kommentieren die setCursorToStringConverter()
Methode aus, dann sehe ich eine Liste der verfügbaren Optionen, basierend auf dem text, den ich eingegeben in dieser Ansicht. Jedoch, da es keine convertToString()
Methode implementiert, dann die terminateToken()
- Methode der benutzerdefinierten Tokenizer
erhält nicht die Zeichenfolge, die ich beabsichtigen, es zu werden, sondern eine repräsentative Zeichenkette von der cursor-Objekt, da der cursor wurde nicht verwendet, um den aktuellen string-Wert, der die gewünschte Spalte in der resultierenden Abfrage.
Hat jemand umsetzen können, die Kombination der drei Klassen (CursorLoader/LoaderManger
MultiAutoCompleteTextView
und Tokenizer
) ?
Bin ich in die richtige Richtung mit diesem, oder ist das einfach nicht möglich?
Ich in der Lage, implementieren eine benutzerdefinierte MultiAutoCompleteTextView
gesichert durch eine SimpleCursorAdapter
zusammen mit einer benutzerdefinierten Tokenizer
. Ich Frage mich nur, ob das möglich zu implementieren, diese mit einem CursorLoader
statt, da im Strikten Modus beschwert sich über den cursor in MultiAutoCompleteTextView
nicht explizit geschlossen.
Jegliche Hilfe würde sehr geschätzt werden.
public class CustomMultiAutoCompleteTextView extends MultiAutoCompleteTextView
implements LoaderManager.LoaderCallbacks<Cursor> {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private Messenger2 mContext;
private RecipientsCursorAdapter mAdapter;
private ContentResolver mContentResolver;
private final char delimiter = ' ';
private CustomMultiAutoCompleteTextView mView;
//If non-null, this is the current filter the user has provided.
private String mCurFilter;
//These are the Contacts rows that we will retrieve.
final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME };
public CustomMultiAutoCompleteTextView(Context c) {
super(c);
init(c);
}
public CustomMultiAutoCompleteTextView(Context c, AttributeSet attrs) {
super(c, attrs);
init(c);
}
private void init(Context context) {
mContext = (Messenger2) context;
mContentResolver = mContext.getContentResolver();
mView = this;
mAdapter = new RecipientsCursorAdapter(mContext, 0, null, new String[0], new int[0], mContext);
mAdapter.setCursorToStringConverter(new CursorToStringConverter() {
@Override
public CharSequence convertToString(Cursor c) {
String contactName = c.getString(c.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
return contactName;
}
});
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d(DEBUG_TAG, "onTextChanged()");
if (!s.equals(""))
mCurFilter = s.toString();
else
mCurFilter = "";
mContext.getLoaderManager().restartLoader(0, null, mView);
}
@Override
public void afterTextChanged(Editable s) {
}
});
setAdapter(mAdapter);
setTokenizer(new SpaceTokenizer());
mContext.getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//This is called when a new Loader needs to be created. This
//sample only has one Loader, so we don't care about the ID.
//First, pick the base URI to use depending on whether we are
//currently filtering.
Log.d(DEBUG_TAG, "onCreateLoader()");
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_FILTER_URI,Uri.encode(mCurFilter));
} else {
baseUri = ContactsContract.Contacts.CONTENT_URI;
}
//Now create and return a CursorLoader that will take care of
//creating a Cursor for the data being displayed.
String selection = "((" + ContactsContract.Contacts.DISPLAY_NAME
+ " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.Contacts.DISPLAY_NAME + " != '' ))";
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC";
return new CursorLoader(mContext, baseUri, CONTACTS_SUMMARY_PROJECTION,
selection, null, sortOrder);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//Swap the new cursor in. (The framework will take care of closing
//the old cursor once we return.)
Log.d(DEBUG_TAG, "onLoadFinished()");
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
//This is called when the last Cursor provided to onLoadFinished()
//above is about to be closed. We need to make sure we are no
//longer using it.
Log.d(DEBUG_TAG, "onLoaderReset()");
mAdapter.swapCursor(null);
}
private class SpaceTokenizer implements Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != delimiter) {
i--;
}
while (i < cursor && text.charAt(i) == delimiter) {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == delimiter) {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
Log.d(DEBUG_TAG, "terminateToken()");
int i = text.length();
while (i > 0 && text.charAt(i - 1) == delimiter) {
i--;
}
if (i > 0 && text.charAt(i - 1) == delimiter) {
return text;
} else {
CharSequence contactName = createContactBubble(text);
return contactName;
}
}
}
}
UPDATE 1
Ich bin jetzt ruft die setStringConversionColumn()
- Methode anstelle der setCursorToStringConverter()
@Olaf vorgeschlagen. Ich habe die Einstellung in der onLoadFinished()
da dies die einzige Zeit, die Cursor
verfügbar ist, da dies die Umsetzung einer LoaderManger
.
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//Swap the new cursor in. (The framework will take care of closing
//the old cursor once we return.)
Log.d(DEBUG_TAG, "onLoadFinished()");
mAdapter.setStringConversionColumn(data.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
mAdapter.swapCursor(data);
}
Funktioniert dies bei der Auswahl einer Position für die MultiAutoCompleteTextView
aber wird nicht zulassen, dass mehrere Elemente ausgewählt werden, die in der MultiAutoCompleteTextView
.
Ich vermute, es gibt einige Problem mit der onTextChanged()
Methode, da ruft es restartLoader()
. Dies funktioniert für den ersten Eintrag in dieser Ansicht, aber nicht für die folgenden Einträge. Ich bin mir nicht sicher, ob an dieser Stelle was falsch ist.
UPDATE 2
Also ich habe erkannt das Problem. Das problem ist das TextWatcher ist onTextChanged()
Methode. Nach der Auswahl zu beenden, das erste token ( sagen wir mal der token "Joe Johnson" ), dann die Eingabe mehr Zeichen in diesem MultiAutoCompleteTextView
( wie al
) der Wert von arg s
, übergeben bekommt in die onTextChanged()
- Methode enthält nun nicht nur die zusätzlich hinzugefügten Charaktere, aber auch die Zeichen aus den Zeichen, die zuvor beendet wurden ( der Wert des s
an dieser Stelle ist Joe Johnson al
). Jetzt wird der Wert von mCursor
festgelegt wird, zu Joe Johnson al
die anschließend übergeben bekommt in die Abfrage in onCreateLoader()
die offensichtlich keine Ergebnisse zurückgeben. Gibt es irgendwelche Möglichkeiten, um mit dieser situation? Ich bin offen für alle Vorschläge.
UPDATE 3
Wenn ich implementiert eine benutzerdefinierte MultiAutoCompleteTextView
gesichert durch eine SimpleCursorAdapter
zusammen mit einer benutzerdefinierten Tokenizer
ich FilterQueryProvider
wie diese:
mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
Log.d(DEBUG_TAG, "runQuery() : constraint " + constraint);
Uri baseUri;
if (constraint != null) {
baseUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,
Uri.encode(constraint.toString()));
} else {
baseUri = ContactsContract.Contacts.CONTENT_URI;
}
String selection = "((" + ContactsContract.Contacts.DISPLAY_NAME
+ " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.Contacts.DISPLAY_NAME + " != '' ))";
final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME};
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC";
Cursor c = mContentResolver.query(baseUri,
CONTACTS_SUMMARY_PROJECTION, selection, null, sortOrder);
return c;
}
});
Und für einige Grund, die runQuery()
Methode aufgerufen wird, wird zweimal von den TextWatcher ist onTextChanged()
Methode:
public void onTextChanged(CharSequence s, int start, int before,
int count) {
Log.d(DEBUG_TAG, "onTextChanged() : s " + s);
mAdapter.getFilterQueryProvider().runQuery(s);
}
So, in meinem vorherigen Beispiel, die constraint
variable, die übergeben bekommt in die runQuery()
Methode das erste mal ist Joe Johnson al
. Dann das zweite mal runQuery()
- Methode aufgerufen, die den Wert der constraint
variable al
. Ich weiß nicht, warum die runQuery()
- Methode wird ausgeführt, zweimal, wenn Ihr nur einmal aufgerufen, in der onTextChanged()
Methode.
InformationsquelleAutor der Frage |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Grundsätzlich Androiden AutoVervollständigen textview ist nicht sehr mächtig, ich habe beim Umgang mit größeren Mengen an Daten, was ich zu tun ist, halte ich eine text-change-listener, um das Bearbeiten von text für die Suche, und dann immer, wenn was geändert wird, auf die text Bearbeiten, Abfragen Datenbank.
Wenn dies könnte helfen, jemand, platzieren Sie ein edittext auf onCreate
So, in den adapter, müssen Sie erstellen eine getFilter () - Methode...
InformationsquelleAutor der Antwort