ArrayAdapter 较晚从 AutoCompleteTextAdapter 中的 Webservice 更新

发布于 2024-11-18 04:25:25 字数 1341 浏览 1 评论 0原文

我有一个与 ArrayAdapter 一起使用的 AutocompleteTextView。当文本更改时,适配器会通过 Web 服务进行更新。此更新是在 AsyncTask 中完成的,这应该是一个很好的实践。这或多或少是有效的,因为按下每个键后的建议都是基于上一个按下的键中检索到的字符串。 此页面有几个相关的问题,但没有一个答案对我有用。无论如何,我有一个解决方案,但效率低下,我不知道为什么“官方解决方案”失败。

我认为关键在于后台更新 ArrayAdapter 的函数。这就是我在异步调用 Web 服务时所做的事情:

private class DoAutoCompleteSearch extends AsyncTask<String, Void, Map<String, String>> {

    @Override
    protected Map<String, String> doInBackground(String... params) {

        // Ask the webservice for data
        Map<String, String> autoComplete = GetResource.dataList(params[0]);
        return autoComplete;
    }

    @Override
    protected void onPostExecute(Map<String, String> result) {

        //mAutoCompleteAdapter.clear();    * This should work but does not *

/* If it is set a new adapter in the AutoCompleteTextView, the whole thing works properly */

    mAutoCompleteAdapter = new ArrayAdapter<String>(mAutoCompleteAdapter.getContext(), android.R.layout.simple_dropdown_item_1line);
    mACTV.setAdapter(mAutoCompleteAdapter);

        for (Map.Entry<String, String> entry : result.entrySet()) {
            mAutoCompleteAdapter.add(entry.getKey());
        }
    }
}

我尝试过使用 mAutoCompleteAdapter.clear() 并在各处设置 mAutoCompleteAdapter.notifyDataSetChanged() ,但它没有用。

I have an AutocompleteTextView working with an ArrayAdapter. The adapter is updated from a webservice, when the text changes. This updated is done in an AsyncTask, what is supposed to be a good practice. This is working more or less, because the suggestions after every key pressed are based on the strings retrieved in the previous key pressed.
There is a couple of problems related is this page, but none of the answers works for me. Anyway, I had a solution, but is inefficient and I don't know why the "official solution" fails.

I think that the key is in the function that udpates de ArrayAdapter in the background. This it what I do in the asynchronous call to the webservices:

private class DoAutoCompleteSearch extends AsyncTask<String, Void, Map<String, String>> {

    @Override
    protected Map<String, String> doInBackground(String... params) {

        // Ask the webservice for data
        Map<String, String> autoComplete = GetResource.dataList(params[0]);
        return autoComplete;
    }

    @Override
    protected void onPostExecute(Map<String, String> result) {

        //mAutoCompleteAdapter.clear();    * This should work but does not *

/* If it is set a new adapter in the AutoCompleteTextView, the whole thing works properly */

    mAutoCompleteAdapter = new ArrayAdapter<String>(mAutoCompleteAdapter.getContext(), android.R.layout.simple_dropdown_item_1line);
    mACTV.setAdapter(mAutoCompleteAdapter);

        for (Map.Entry<String, String> entry : result.entrySet()) {
            mAutoCompleteAdapter.add(entry.getKey());
        }
    }
}

I have tried with mAutoCompleteAdapter.clear() and setting mAutoCompleteAdapter.notifyDataSetChanged() everywhere, but it is useless.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抚你发端 2024-11-25 04:25:25

我也尝试了很多方法来让这种方法发挥作用,但没有比你更好的成功。但我找到了另一种方法来实现你想要的;扩展 ArrayAdapter 并实现 Filterable。当工作线程中的 AutoCompleteTextView 调用时,此类将实际从数据库中获取数据:

public class MyAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {

    private List<String> mData = new ArrayList<String>();
    private Server mServer;

    public MyAutoCompleteAdapter(Server server, Context context, int textViewResourceId) {
        super(context, textViewResourceId);
        mServer = server;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public String getItem(int index) {
        return mData.get(index);
    }

    @Override
    public Filter getFilter() {
        Filter myFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // This method is called in a worker thread

                FilterResults filterResults = new FilterResults();
                if(constraint != null) {
                    try {
                        // Here is the method (synchronous) that fetches the data
                        // from the server
                        List<String> results = mServer.searchForItems(constraint.toString());
                        filterResults.values = results;
                        filterResults.count = results.size();
                    }
                    catch(Exception e) {}

                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence contraint, FilterResults results) {
                if(results != null && results.count > 0) {
                    mData = (List<String>)results.values;
                    notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return myFilter;
    }
}

编辑:我改进了上面的代码,因为我有时会遇到异常 java.lang。 IllegalStateException:适配器的内容已更改,但 ListView 未收到通知。为了解决这个问题,我将 mData 的更新移至 publishResults()

I also tried alot to get this approach working, but didn't succeed any better than yourself. But I found another way to accomplish what you want; extend ArrayAdapter and implement Filterable. This class will be doing the actual fetching from the database, when called by the AutoCompleteTextView in a worker thread:

public class MyAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {

    private List<String> mData = new ArrayList<String>();
    private Server mServer;

    public MyAutoCompleteAdapter(Server server, Context context, int textViewResourceId) {
        super(context, textViewResourceId);
        mServer = server;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public String getItem(int index) {
        return mData.get(index);
    }

    @Override
    public Filter getFilter() {
        Filter myFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // This method is called in a worker thread

                FilterResults filterResults = new FilterResults();
                if(constraint != null) {
                    try {
                        // Here is the method (synchronous) that fetches the data
                        // from the server
                        List<String> results = mServer.searchForItems(constraint.toString());
                        filterResults.values = results;
                        filterResults.count = results.size();
                    }
                    catch(Exception e) {}

                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence contraint, FilterResults results) {
                if(results != null && results.count > 0) {
                    mData = (List<String>)results.values;
                    notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return myFilter;
    }
}

EDIT: I have improved the above code since I sometimes got the exception java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. To fix this, I moved the updating of mData to publishResults().

缺⑴份安定 2024-11-25 04:25:25

这段代码片段在我的应用程序中对我有用。将其放入包含 ListView 的活动中:

@Override
public void onActivityResumed() //
{
    if (favoritesHaveChanged(activity, productString)) //
    {
        m_adapter.clear();
        performAsyncTaskWithCallBack(activity);
    }
}

回调将是触发的事件侦听器。通常,通过 AsyncTasks,您可以在 AsyncTask 中使用 onPostExecute()

This code snippet worked for me in my app. Put this in your activity that contains the ListView:

@Override
public void onActivityResumed() //
{
    if (favoritesHaveChanged(activity, productString)) //
    {
        m_adapter.clear();
        performAsyncTaskWithCallBack(activity);
    }
}

The callback will be an event listener that is triggered. Typically with AsyncTasks you can use onPostExecute() in your AsyncTask.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文