【问题标题】:Populate autoCompleteTextView with a firebase Database使用 firebase 数据库填充 autoCompleteTextView
【发布时间】:2018-09-25 14:55:21
【问题描述】:

我正在开发一个依赖 SQLite 数据库来填充 autoCompleteTextView 的应用,因此当用户输入一些文本时,应用会根据用户输入显示建议列表。

我想进行下一步并实现了一个简单的 Firebase 数据库来存储autoCompleteTextview 所需的单词列表。由于我是使用 Firebase 的新手,因此无法从 Firebase 数据库中获取数据。

我真的不知道如何开始,我想我应该创建一个自定义的 ArrayAdapter 并覆盖它的方法,以便在每次更改 AutocompleteTextView 中的文本时动态搜索数据库 或搜索数据库中的所有单词并将它们放入单个ArrayList 以与TextView. 一起使用

希望收到您的来信,非常感谢。

【问题讨论】:

  • 我不确定您的想法是否可行,因为 firebase 数据库不具备 SQL 的查询功能——我认为不可能获得与您的用户搜索内容相匹配的结果。我认为您可能会定期下载完整的密钥列表。从好的方面来说,您可以将数据库设置为仅检索密钥,将这些密钥存储在本地,然后使用本地密钥映射管理您的搜索。 (我不是专家,但老实说,我认为这是你能做的最好的)。
  • 更新,我对新的 Firebase firestore 没有太多经验,但它可能具有查询功能,可以满足您的需求...
  • 所以你基本上想使用firebase数据库实现搜索。?
  • 我想它是一个连续搜索,因为它连接到 AutocompleteTextview,从固定数据集或每次用户输入文本时直接连接到 FirebaseDatabase。

标签: android database firebase firebase-realtime-database


【解决方案1】:

我使用 Firestore 做了类似的事情,创建了一个自定义 ArrayAdapter,它侦听 Firestore 查询并实现 Filterable

public class ProductAdapter extends ArrayAdapter<Product>
        implements Filterable, EventListener<QuerySnapshot> {

    private final Object mLock = new Object();
    private static final java.lang.String TAG = "Product Adapter";
    private ArrayList<Product> mProducts  = new ArrayList<>();
    private ArrayList<Product> mOriginalValues;
    private ArrayFilter mFilter;
    private CharSequence mFilterPrefix;
    private Query mQuery;
    private ListenerRegistration mRegistration;

    public ProductAdapter(Context context, int resource, Query query) {
        super(context, resource);
        mQuery = query;
    }

    @Override
    public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {

        if (e != null) {
            Log.w(TAG, "onEvent:error", e);
            return;
        }

        for (DocumentChange change : documentSnapshots.getDocumentChanges()) {

            switch (change.getType()) {
                case ADDED:
                    onDocumentAdded(change);
                    break;
                case MODIFIED:
                    onDocumentModified(change);
                    break;
                case REMOVED:
                    onDocumentRemoved(change);
                    break;
            }

            if (mFilterPrefix != null) {
                getFilter().filter(mFilterPrefix);
            }
        }
    }

    public void startListening() {
        if (mQuery != null && mRegistration == null) {
            mRegistration = mQuery.addSnapshotListener(this);
        }
    }

    public void stopListening() {
        if (mRegistration != null) {
            mRegistration.remove();
            mRegistration = null;
        }

        synchronized (mLock) {
            if (mOriginalValues != null) {
                mOriginalValues.clear();
            } else {
                mProducts.clear();
            }
        }
        notifyDataSetChanged();
    }

    public void setQuery(Query query) {
        stopListening();

        synchronized (mLock) {
            if (mOriginalValues != null) {
                mOriginalValues.clear();
            }
            mProducts.clear();
        }
        notifyDataSetChanged();

        mQuery = query;
        startListening();
    }

    protected void onDocumentAdded(DocumentChange change) {
        synchronized (mLock) {
            if (mOriginalValues != null) {
                mOriginalValues.add(change.getNewIndex(), change.getDocument().toObject(Product.class));
            } else {
                mProducts.add(change.getNewIndex(), change.getDocument().toObject(Product.class));
            }
        }
        notifyDataSetChanged();
    }

    protected void onDocumentModified(DocumentChange change) {
        synchronized (mLock) {
            if (change.getOldIndex() == change.getNewIndex()) {
                if (mOriginalValues != null) {
                    mOriginalValues.set(change.getOldIndex(), change.getDocument().toObject(Product.class));
                } else {
                    mProducts.set(change.getOldIndex(), change.getDocument().toObject(Product.class));
                }
            } else {
                if (mOriginalValues != null) {
                    mOriginalValues.remove(change.getOldIndex());
                    mOriginalValues.add(change.getNewIndex(), change.getDocument().toObject(Product.class));
                } else {
                    mProducts.remove(change.getOldIndex());
                    mProducts.add(change.getNewIndex(), change.getDocument().toObject(Product.class));
                }
            }
        }
        notifyDataSetChanged();
    }

    protected void onDocumentRemoved(DocumentChange change) {
        synchronized (mLock) {
            if (mOriginalValues != null) {
                mOriginalValues.remove(change.getOldIndex());
            } else {
                mProducts.remove(change.getOldIndex());
            }
        }
        notifyDataSetChanged();
    }

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

    @Override
    public Product getItem(int position){
        return mProducts.get(position);
    }

    @Override
    public long getItemId(int position){
        return position;
    }

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

        TextView label = (TextView) super.getView(position, convertView, parent);
        label.setText(mProducts.get(position).getName());
        return label;
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        TextView label = (TextView) super.getDropDownView(position, convertView, parent);
        label.setText(mProducts.get(position).getName());
        return label;
    }

    @Override
    public @NonNull Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }

    private class ArrayFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            final FilterResults results = new FilterResults();

            mFilterPrefix = prefix;

            if (mOriginalValues == null) {
                synchronized (mLock) {
                    mOriginalValues = new ArrayList<>(mProducts);
                }
            }

            final ArrayList<Product> values;
            synchronized (mLock) {
                values = new ArrayList<>(mOriginalValues);
            }

            if (prefix == null || prefix.length() == 0) {
                results.values = values;
                results.count = values.size();

            } else {
                final String prefixString = prefix.toString().toLowerCase();
                final int count = values.size();
                final ArrayList<Product> newValues = new ArrayList<>();

                for (int i = 0; i < count; i++) {
                    final Product product = values.get(i);
                    final String valueText = product.getName().toLowerCase();

                    if (valueText.startsWith(prefixString)) {
                        newValues.add(product);
                    } else {
                        final String[] words = valueText.split(" ");
                        if (words.length > 1) {
                            if (words[words.length - 1].startsWith(prefixString)) {
                                newValues.add(product);
                            } else {
                                for (int j = words.length - 2; j > 0; j--) {
                                    words[j] = words[j] + " " + words[j + 1];
                                    if (words[j].startsWith(prefixString)) {
                                        newValues.add(product);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                results.values = newValues;
                results.count = newValues.size();

            }

            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

            mProducts = (ArrayList<Product>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

    }

}

然后我将此适配器设置为我的AutoCompleteTextView 的适配器。在我的例子中,我正在通过 AutoCompleteTextView 中显示的名称过滤 Product 类的对象列表,但您可以将其更改为字符串。

需要明确的是,此方法侦听整个文档列表(在我的例子中为产品)的查询,然后在本地过滤它们,而不是根据AutoCompleteTextView 中键入的文本进行查询。这样,您无需在每次输入新字母时都进行查询,并且如果 Firestore 数据库发生更改,列表会自动更新。如果您想在每次文本更改时进行新查询,您可以尝试使用 this 之类的内容。

【讨论】:

    【解决方案2】:

    不完全是为了自动完成,而是为了在 recyclerview 中搜索和过滤项目,我使用了这种方法。

    @Override
                public boolean onQueryTextChange(String s) {
                    Query search_query = productRef.orderBy("productName", Query.Direction.ASCENDING).startAt(s).endAt(s + "\uf8ff");
                    FirestoreRecyclerOptions<Product> options = new FirestoreRecyclerOptions.Builder<Product>().setQuery(search_query, Product.class).build();
                    productAdapter = new ProductAdapter(options);
                    recyclerView.setHasFixedSize(true);
                    recyclerView.setLayoutManager(new LinearLayoutManager(Product_List.this));
                    recyclerView.setAdapter(productAdapter);
                    productAdapter.startListening();
                    return false;
                }
    

    【讨论】:

      猜你喜欢
      • 2016-07-23
      • 1970-01-01
      • 1970-01-01
      • 2018-11-22
      • 2020-06-06
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      相关资源
      最近更新 更多