【问题标题】:Android : AutoCompleteTextView listview scroll listener (for endless scrolling)Android:AutoCompleteTextView listview 滚动监听器(用于无限滚动)
【发布时间】:2015-05-30 08:33:07
【问题描述】:



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

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

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

谢谢大家:)

我的片段代码

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

    }

}

【问题讨论】:

    标签: android listview autocompletetextview


    【解决方案1】:

    很遗憾,没有用于自动完成的OnScrollListener 接口,但我认为您可能能够解决这个问题。

    以下是我认为的配方:

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

    我注意到您为偏移量硬编码了“0”。您将希望能够使用该值调用autocomplete。另外,items.clear() 位于 autocomplete 的末尾,并且只有在偏移量为零时才需要这样做。

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

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

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

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

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

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

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

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

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

    我已经完成了这种“无尽”滚动,ListViewOnScrollListener 调用AsyncTask 以逐页返回搜索结果,我认为它对我有用的是请求响应包含一个总大小,所以我可以将它用于getCount()

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

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

    【讨论】:

    • getView 中的适配器方法是一个绝妙的主意,但代码很难看,我希望 AOSP 提供对其中的 ListView 的访问。
    猜你喜欢
    • 1970-01-01
    • 2018-09-21
    • 2015-09-20
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2012-09-13
    • 2014-11-15
    相关资源
    最近更新 更多