安卓 : AutoCompleteTextView listview scroll listener (for endless scrolling)

标签 android listview autocompletetextview



我正在使用 AutoCompleteTextView 让我的 Android 应用程序的用户使用自定义 Web 服务搜索内容:它按预期工作,但目前,我找不到实现“无限滚动”的方法“在下拉 ListView 上。

现在,我的 AutoCompleteTextView 适配器是一个实现 Filterable 接口(interface)的 ArrayAdapter;每当用户更改 AutoCompleteTextView 的文本时,过滤器的 performFiltering() 方法就会被触发,我可以向自定义 Web 服务发出 HTTP 请求以显示适当的内容。但我想在用户滚动下拉菜单时加载更多内容,这是一个分页系统,这样我就可以避免一次加载数百个结果......但我不知道如何做!< br/>

  • 如何获取与 AutoCompleteTextView 关联的 ListView 实现我自己的 OnScrollListener/EndlessScrollListener ?
  • 还有其他办法吗?

谢谢大家:)

我的 fragment 代码

AutoCompleteTextView search = (AutoCompleteTextView) view.findViewById(R.id.search);

SearchAdapter searchAdapter = new SearchAdapter(getActivity(), 0);

search.setAdapter(searchAdapter);

我的适配器代码(已编辑)

class SearchAdapter extends ArrayAdapter<Parcelable> implements Filterable {

    Integer numberPerPage = 10;
    Boolean moreDataIsAvailable = false;

    FragmentActivity activity;
    public ArrayList<Parcelable> items = new ArrayList<Parcelable>();

    public SearchAdapter(FragmentActivity a, int textViewResourceId) {
        super(a, textViewResourceId);
        activity = a;
    }

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

    @Override
    public Parcelable getItem(int index) {
        if(items.size() > index) {
            return items.get(index);
        } else {
            return null;
        }
    }

    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null && constraint.toString().length() >= 3) {
                    autocomplete(constraint.toString(), items);
                    filterResults.count = items.size();
                    filterResults.values = items;
                } else {
                    items.clear();
                    filterResults.count = items.size();
                    filterResults.values = items;
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return filter;
    }

    static class ViewHolder {
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder = null;

        View rowView = convertView;

        if (rowView == null) {

            rowView = LayoutInflater.from(activity).inflate(R.layout.search_row, parent, false);
            holder = new ViewHolder();
            rowView.setTag(holder);

        } else {

            holder = (ViewHolder) rowView.getTag();

        }

        // Setting my row data

        return rowView;

    }

    private void autocomplete(String input, ArrayList<Parcelable> items) {

        ArrayList<Parcelable> data = new ArrayList<Parcelable>();

        try {

            RequestHandler request = new RequestHandler();

            JSONObject requestParameters = new JSONObject();
            requestParameters.put("offset", 0);
            requestParameters.put("keyword", input);
            requestParameters.put("limit", numberPerPage);

            ResponseDescription response = request.request(activity, requestParameters);

            if(!response.error) {

                JSONArray searchedItems = response.getJSONArray("items");

                if(searchedItems.length() == numberPerPage) {
                    moreDataIsAvailable = true;
                } else {
                    moreDataIsAvailable = false;
                }

                for(int i = 0 ; i < searchedItems.length(); i++) {

                    JSONObject searchedItem = searchedItems.getJSONObject(i);

                    MyObject object = new MyObject();
                    object.initWithJSONObject(searchedItem);
                    data.add(object);

                }
            }

        } catch (Exception e) {

            e.printStackTrace();

        }

        items.clear();
        items.addAll(data);

    }

}

最佳答案

不幸的是,没有用于自动完成的 OnScrollListener 接口(interface),但我认为您也许可以解决这个问题。

这就是我认为的食谱:

  • 向您的autocomplete 方法中添加另一个参数作为偏移量。

我注意到您对偏移量进行了硬编码“0”。您将希望能够使用该值调用autocomplete。此外,您在 autocomplete 末尾有 items.clear() ,并且只有在偏移量为零时才需要执行此操作。

  • 为您的自动完成方法创建一个 AsyncTask

或者除了 Filter 中的 performFiltering 方法之外,还可以在后台运行 autocomplete 的方法。此异步任务需要访问您的适配器,以便它可以将其结果添加到 items 列表中,并像过滤器一样调用 notifyDataSetChanged()

您的适配器需要保留对此任务的引用,以便在用户再次开始输入时您可以取消它。

  • getView() 添加一些逻辑以执行异步任务。

我们没有 OnScrollListener,因此我们将使用 getView() 作为其代理。

设置启动下一个请求的常量阈值。它需要小于您的 numberPerPage,所以我们以“5”为例。

现在,当 ListView 调用 getView() 且位置距离末尾在阈值内时,执行异步任务。例如,在第一个过滤操作之后,列表中有 10 个项目。当 ListView 请求第 5 项的 View 时,启动异步任务,偏移量等于列表大小 - 在本例中为 10(以获取第 11-20 项)。

我的假设是,ListView 仅当用户向下滚动到该项目时才会请求项目 View 。

  • performFiltering() 中,取消任何正在运行的异步任务。

我已经完成了这种类型的“无尽”滚动,使用 ListViewOnScrollListener 调用 AsyncTask 来逐页返回搜索结果,我认为它对我有用的是请求响应包含总大小,因此我能够将其用于 getCount()

我还使用自动完成来获取远程结果,但我不必对这些结果进行分页。事实上,我想我只是在输入更改时运行了异步任务,并且我的过滤方法没有操作。

结合自动完成和分页,您会遇到不同的情况。如果用户在异步任务更新列表之前到达列表末尾,则滚动下拉列表时可能会出现一些卡顿行为。因此,您可能需要调整页面大小、阈值甚至 getCount() 的返回值才能获得可接受的滚动体验。但我认为这是可行的。

关于安卓 : AutoCompleteTextView listview scroll listener (for endless scrolling),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29276545/

相关文章:

android - 只有在另一个类中完成使用 Parse.com 的异步数据导入后,才在 Android 中填充 ListView

Android AutoCompeleteTextView 没有给出正确的结果

java - AutoCompleteTextview 不显示第一个字符条目的下拉建议

android: 使用 SimpleAdapter 更新 ListView

android - ScrollView 不起作用

Android - 在 html 代码中播放 html5 <video>

android - 通过从数据库填充的 ListView 进行搜索

c# - 如何将 SelectedListViewItemCollection 转换为 ListViewItemCollection

android - AutoCompleteTextView 不显示下拉菜单

android - MQTT 安全 - 如何防止滥用者订阅主题?