Android : AutoCompleteTextView 列表视图滚动侦听器(用于无限滚动)

Android : AutoCompleteTextView listview scroll listener (for endless scrolling)



我正在使用 AutoCompleteTextView 让我的 android 应用程序的用户使用自定义网络服务搜索内容:它按预期工作,但目前我找不到一种在下拉列表视图上实现 "Endless Scrolling" 的方法。

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

谢谢大家:)

我的片段代码

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 自动完成界面,但我认为您可以解决这个问题。

这是我认为的食谱:

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

我注意到您将偏移量硬编码为“0”。您将希望能够调用 autocomplete 并为其赋值。另外,在 autocomplete 的末尾还有 items.clear() 并且您只想在偏移量为零时执行此操作。

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

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

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

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

我们没有 OnScrollListener,所以我们将使用 getView() 作为一种代理。

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

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

我的假设是 ListView 仅在用户向下滚动到该项目时才请求项目视图。

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

我已经完成了这种类型的 "endless" 滚动,其中 ListView 逐页调用 AsyncTaskOnScrollListener 到 return 搜索结果,我认为它对我有用的原因是请求响应包含总大小,因此我能够将其用于 getCount()

我还使用自动完成功能获取远程结果,但我不必分页这些结果。事实上,我想我只是 运行 当输入改变并且我的过滤方法是空操作时的异步任务。

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