too*_*o42 33 android stringtokenizer autocompletetextview android-cursorloader
因此,我无法在使用自定义的同时扩展MultiAutoCompleteTextView
和支持它.这个问题特别随着电话而上升.在其中有一个游标作为参数方法具有在第一调用此方法有效的和未封闭的光标.但是,后续调用会导致空游标或关闭游标.我猜这与管理如何有关. CursorLoader
Tokenizer
mAdapter.setCursorToStringConverter();
convertToString()
LoaderManager
CursorLoader
如果我将setCursorToStringConverter()
方法注释掉,那么我会根据我在此视图中输入的文本看到可用选项列表.但是,由于没有convertToString()
实现terminateToken()
方法,因此自定义方法Tokenizer
不接收我想要的字符串,而是接收游标对象的代表字符串,因为游标尚未用于获取当前字符串值在得到的查询中的所需列的.
任何人都已经能够实现三类的组合(CursorLoader/LoaderManger
,MultiAutoCompleteTextView
,和Tokenizer
)?
我是否朝着正确的方向前进,或者这根本不可能?
我已经能够实现一个自定义MultiAutoCompleteTextView
支持SimpleCursorAdapter
的自定义Tokenizer
.我只是想知道是否有可能使用a来实现它CursorLoader
,因为严格模式抱怨光标MultiAutoCompleteTextView
没有被明确关闭.
任何帮助将不胜感激.
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新1
我现在调用setStringConversionColumn()
方法而不是setCursorToStringConverter()
@Olaf建议.我已经设置了这个,onLoadFinished()
因为这是唯一Cursor
可用的,因为这是实现a 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);
}
Run Code Online (Sandbox Code Playgroud)
这适用于选择一个项目MultiAutoCompleteTextView
,但不允许在中选择多个项目MultiAutoCompleteTextView
.
我猜这个onTextChanged()
方法存在一些问题,因为它调用了restartLoader()
.这适用于此视图中的第一个条目,但不适用于后续条目.我现在不太确定什么是错的.
更新2
所以我发现了这个问题.问题是TextWatcher的onTextChanged()
方法.在选择终止第一个令牌之后(假设令牌是"Joe Johnson"),然后输入更多的字符MultiAutoCompleteTextView
(例如al
)s
,传递给onTextChanged()
方法的arg的值现在不仅包含额外添加的字符还有先前被终止的令牌中的字符(此时的值s
是Joe Johnson al
).现在,mCursor
get 的值设置为Joe Johnson al
随后传递给查询,onCreateLoader()
其中显然不会返回任何结果.这种情况有什么方法吗?我对任何建议持开放态度.
更新3
当我实现一个MultiAutoCompleteTextView
由自定义支持SimpleCursorAdapter
的自定义Tokenizer
我设置FilterQueryProvider
如下:
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;
}
});
Run Code Online (Sandbox Code Playgroud)
由于某种原因,该runQuery()
方法从TextWatcher的onTextChanged()
方法被调用两次:
public void onTextChanged(CharSequence s, int start, int before,
int count) {
Log.d(DEBUG_TAG, "onTextChanged() : s " + s);
mAdapter.getFilterQueryProvider().runQuery(s);
}
Run Code Online (Sandbox Code Playgroud)
所以在我之前的例子中,第一次constraint
传递给runQuery()
方法的变量是Joe Johnson al
.然后第二次runQuery()
调用方法的constraint
变量值为al
.我不知道为什么该runQuery()
方法只在onTextChanged()
方法中调用一次时运行两次.
基本上,android自动完成文本视图不是很强大,当我必须处理大量数据时,我所做的是,我为编辑文本保留一个文本更改侦听器以进行搜索,然后每当编辑文本上发生某些更改时,它查询数据库。
如果这可能对某人有帮助,请在 onCreate 上放置一个编辑文本
EditText etSearch = (EditText)findViewById(R.id.etSearchBox);
etSearch.addTextChangedListener(filterTextWatcher);
//The filterTextWatcher is
private TextWatcher filterTextWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before,int count) {
adapter.getFilter().filter(s.toString());
}
};
Run Code Online (Sandbox Code Playgroud)
因此,在您的适配器中,您需要创建一个 getFilter() 方法......
@Override
public Filter getFilter() {
if (nameFilter == null) {
nameFilter = new NameFilter();
}
return nameFilter;
}
private class NameFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
Cursor cursor = null;
// get your cursor by passing appropriate query here
results.values = cursor;
results.count = cursor.getCount();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyDataSetChanged();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12664 次 |
最近记录: |