【问题标题】:Not able while search through Firebase recycler view通过 Firebase 回收器视图搜索时无法使用
【发布时间】:2018-08-29 10:13:19
【问题描述】:

我试图从我的材料搜索对话框中搜索 Firebase 数据库。我成功地做到了,但问题是我只能通过标题进行搜索(我的数据库也包含标题和描述),尽管我尝试了很多对我没有用的东西。

在某个时候,我成功地为搜索描述创建了另一个搜索功能,但随后它使标题的搜索结果出现异常。

我附上下面的代码可以,请看一下,如果有什么我可以做的搜索标题和描述,请告诉我。

声明和代码(我已经跳过了活动代码中不需要的部分)

    materialSearchBar = homeView.findViewById(R.id.searchBar);
        materialSearchBar.setHint("Search Ad");
        loadSuggest();
        materialSearchBar.setLastSuggestions(suggestList);
        materialSearchBar.setCardViewElevation(10);
        materialSearchBar.addTextChangeListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                List<String> sugest = new ArrayList<String>();
                for (String search : suggestList) {
                    if (search.toLowerCase().contains(materialSearchBar.getText().toLowerCase()))
                        sugest.add(search);
                }
                materialSearchBar.setLastSuggestions(sugest);

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
        materialSearchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() {
            @Override
            public void onSearchStateChanged(boolean enabled) {
                if (!enabled)
                    mallUsers.setAdapter(firebaseRecyclerAdapter);
            }

            @Override
            public void onSearchConfirmed(CharSequence text) {

                startSearch(text);

            }

            @Override
            public void onButtonClicked(int buttonCode) {

            }
        });
// start search and load suggestions methods
    private void startSearch(CharSequence text) {
        String searchText = text.toString();
        Query query1 = mDatabase1.orderByChild("title").startAt(searchText).endAt(searchText + "\uf8ff");
        Query query2 = mDatabase1.orderByChild("description").startAt(searchText).endAt(searchText + "\uf8ff");
        FirebaseRecyclerOptions<Ad> firebaseRecyclerOptions2 = new FirebaseRecyclerOptions
                .Builder<Ad>()
                .setQuery(query1, Ad.class)
                .build();

        searchAdapter = new FirebaseRecyclerAdapter<Ad, UsersViewHolder1>(firebaseRecyclerOptions2) {
            @Override
            protected void onBindViewHolder(@NonNull UsersViewHolder1 holder, int position, @NonNull Ad ad1) {
                holder.setTitle(ad1.getTitle());
                holder.setPrice(ad1.getPrice());
                holder.setCategory(ad1.getCategory());
                holder.setImage(ad1.getImage(), getContext());
                holder.setTime(ad1.getTime());


                String user_id = getRef(position).getKey();
                final String kk = user_id.toString();

                holder.mView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent mew = new Intent(getActivity(), ExpandActivity.class);
                        mew.putExtra("user_id", kk);
                        startActivity(mew);

                    }
                });

            }

            @NonNull
            @Override
            public UsersViewHolder1 onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                View view1 = LayoutInflater.from(parent.getContext()).inflate(R.layout
                                .user_ad_layout, parent,
                        false);

                return new UsersViewHolder1(view1);
            }
        };
        searchAdapter.startListening();
        mallUsers.setAdapter(searchAdapter);


    }


    private void loadSuggest() {
        mDatabase1.orderByKey().addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot postdataSnapshot : dataSnapshot.getChildren()) {
                    Ad item = postdataSnapshot.getValue(Ad.class);
                    if (item != null) {
                        suggestList.add(item.getTitle());
                        suggestList.add(item.getDescription());
                    }
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

【问题讨论】:

    标签: android firebase firebase-realtime-database android-recyclerview


    【解决方案1】:

    根据post,您无法将两个查询传递给单个适配器。所以你可以通过query1query2

    不幸的是,Firebase Realtime 数据库不支持对多个属性的查询(有人用 SQL 术语说“多个 where 子句”),仅支持对单个子属性的查询。因此,您需要创建一个额外的字段来保留这两个字段。因此,要实现这一点,您需要创建一个新字段,该字段在您的数据库中应如下所示:

    Firebase-root
       |
       --- itemId
              |
              --- title: "valueOfTitle"
              |
              --- description: "valueOfDescription"
              |
              --- title_description: "valueOfTitle_valueOfDescription"
    

    如您所见,title_description 属性结合了您要过滤的值。但 Firebase 实时数据库不支持原生索引或搜索对象中的文本字段。此外,下载整个模式以在客户端搜索字段是不切实际的。但是,您可以对小数据集执行此操作,但正如我之前所说,对于大数据集并不实用。要启用 Firebase 实时数据库的全文搜索,我建议您使用第三方搜索服务,例如 Algolia

    与 Firebase 实时数据库不同,Cloud Firestore 允许 compound queries。你应该看看这个。因此,Cloud Firestore 允许在不创建组合属性的情况下进行如下查询。

    itemIdRef.whereEqualTo("title", "valueOfTitle").whereEqualTo("description", "valueOfDescription");
    

    如果您想在 Cloud Firestore 中使用 Algolia,我建议您从 post 中查看我的回答。有关详细信息,我还建议您查看此 video

    【讨论】:

    • 非常感谢您提供的信息,但是当大多数活动都将数据从实时数据库中提取到回收站视图中时,是否建议将广告数据存储在 Firestore 中。
    • 根据您的应用用例,您应该检查是否值得。查看两个实时数据库 here 之间的差异。
    • 好的,我会的,但你认为我的回答对你有帮助吗?
    • 如果您认为我的回答/评论对您有所帮助,请考虑接受并投票。我会很感激的。谢谢!
    【解决方案2】:

    您已经体验过 Firebase 的最低功能,即查询。但是,如果您在 Firebase 上同时上传标题和描述,则可以查询多个值,如下所示:

    user:
    post:
        title: "cake"
        description: "yummy"
        titledescription: "cake_yummy"
    

    类似的东西。 你可以做的另一件事是

    private boolean hasValue = false;
    private boolean hasValue1 = false;
    

    在 onBindViewHolder 中设置值为真,然后使用处理程序延迟查询值一次一个:

    Handler myHandler1 = new Handler();
    Runnable myRunnable1 = new Runnable() {
       @Override
       public void run() {
           // query1 here
       }
    };
    
    Handler myHandler2 = new Handler();
    Runnable myRunnable2 = new Runnable() {
       @Override
       public void run() {
           // query2 here
       }
    };
    

    然后你一次检查一个,直到找到一个值

       if(!hasValue){
         myHandler1.postDelayed(myRunnable1, 1000);
            if(!hasValue1){
               myHandler2.postDelayed(myRunnable2, 1500); 
            } else {
               myHandler1.removeCallbacks(myRunnable1);
               hasValue1 = false;
         } else {
         myHandler2.removeCallbacks(myRunnable2);
         hasValue2 = false;
         }
     }
    

    希望对你有帮助。

    【讨论】:

    • 我怀疑使用处理程序会解决这个问题。如果获取数据的时间大于 1500 毫秒,会发生什么情况?
    • 我用它来处理较小的数据,它就像一个魅力。对于大于 1500 毫秒的数据,您可以使用按钮,单击第一个查询,如果没有,则单击第二个查询。再次使用 Firebase 进行查询是一件很痛苦的事情,因为非常清楚很容易找到存储的数据是必不可少的。
    • 你好 ace 绊倒,我只需要在左侧的查询空间中添加单个查询行还是需要添加其他内容
    • 您可以将 startSearch 更改为 startSearch(CharSequence text, Query querySearch) { FirebaseRecyclerOptions firebaseRecyclerOptions2 = new FirebaseRecyclerOptions .Builder() .setQuery(querySearch, Ad.class) .build( );然后将处理程序放在 onSearchConfirmed 和处理程序 1 startSearch(text, query1) 上的处理程序 2 startSearch(text, query2) 上。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多