当前位置: 首页 > 知识库问答 >
问题:

CursorLoader支持的

柴阳云
2023-03-14

我是在朝着正确的方向前进,还是根本不可能?

我已经能够实现一个自定义MultiAutoCompleteTextView,它由SimpleCursorAdapter和一个自定义的标记器支持。我只是想知道是否可以使用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;
            }
        }

    }

}
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);
}

我猜想ontextchanged()方法有一些问题,因为它调用restartloader()。这适用于该视图中的第一个条目,但不适用于后续条目。在这一点上我不太确定出了什么问题。

更新2

所以我已经确定了问题。问题是TextWatcher的ontextChanged()方法。选择终止第一个令牌后(假设令牌是“Joe Johnson”),然后在这个MultiAutoCompleteTextView中输入更多字符(例如al),传递到ontextChanged()方法的args的值现在不仅包含额外添加的字符,还包含以前终止的令牌中的字符(s的值是Joe Johnson al)。现在,MCursor的值被设置为Joe Johnson al,随后将其传递到oncreateLoader()中的查询中,显然不会返回任何结果。有什么办法可以解决这种情况吗?我对任何建议都持开放态度。

更新3

当我实现由SimpleCursorAdapter和自定义标记器支持的自定义MultiAutoCompleteTextView时,我设置了一个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;
    }
});

出于某种原因,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);
}

共有1个答案

申辉
2023-03-14

基本上,androids自动完成textview并不是很强大,当我必须处理大量的数据时,我所做的是,我保留一个文本更改监听器来搜索编辑文本,然后每当编辑文本上的内容发生变化时,它就查询数据库。

如果这可能对某人有所帮助,请在onCreate上放置edittext

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());
        }
    };  

因此,在您的适配器中,您需要创建一个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();
        }
    }
 类似资料:
  • 我有两个1:N关系的表,我使用内容提供程序和CursorLoader。 我如何使连接查询与光标加载器一起工作?我可以用内容提供程序内部的rawSql来解决它,但如何在游标加载器构造函数中做到这一点我无法理解。 CursorLoader(上下文上下文,Uri Uri,String[]投影,String selection,String[]selectionArgs,String sortOrder)

  • 对于Requests,如果你有问题或者建议,可以通过下面几种方法得到支持: StackOverflow 如果你的问题不包含敏感或私有信息,或者你能将这些信息匿名化,那你就可以在 StackOverflow 上使用 python-requests 标签提问。 发送推文 如果你的问题在140个字符内描述,欢迎在 twitter 上发送推文至 @kennethreitz, @sigmavirus24,

  • 我需要在JAX-WS中通过客户端连接到外部服务器。客户端在Wildfly 8上运行。使用Java8连接是正常的。但我在Java7中连接到服务器时遇到了问题(我尝试了u45、67、79)。服务器端安全性的属性为https://www.ssllabs.com/ssltest/analyze.html?d=app.bundesnetzagentur.de 在部分“密码套件”中有四个密码。源代码不应支持J

  • WebSocket 规范定义了一种 API,可在网络浏览器和服务器之间建立"套接字"连接。 简单地说:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。 Nutz为WebSocket准备了什么? 请下载最新的nutz-plugins-websocket及websocket api, 然后只需要一个类, 即可完成websocket的基础集成. @ServerEndpoint(val

  • 这个特性被喊了好几个版本了,并且先后被报了好几个 Issue: Issue 323 Issue 369 加上今天是个风和日丽的日子,Nutz.Mvc 重构完毕。架构这么灵活强大, 那么我就把这个特性加上吧,呵呵。 注意, Nutz支持的是Restful风格的映射, 但并非一个Restful实现. 如何使用 REST Nutz.Mvc 对于 REST 的支持,包括4个常用方法及通用定义方法: GET

  • ACL (Access Control List, 访问控制列表) 具有 超级用户 的 ACL 没有用户的 ACL: 对于没有身份验证或用户登录的系统尤其有用。 没有资源的 ACL: 某些场景可能只针对资源的类型, 而不是单个资源, 诸如 write-article, read-log等权限。 它不控制对特定文章或日志的访问。 RBAC (基于角色的访问控制) 支持资源角色的RBAC: 用户和资源