在Firebase回收器视图中搜索时无法

时间:2018-08-29 10:13:19

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

我试图从我的材料搜索对话框中搜索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) {

            }
        });
    }

2 个答案:

答案 0 :(得分:1)

根据此post,无法将两个查询传递给单个适配器。因此,您可以传递query1query2

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

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

因此,如您所见,title_description属性将要过滤的值组合在一起。但是Firebase实时数据库不支持本机索引编制或在对象中搜索文本字段。此外,下载整个模式以搜索客户端的字段也不切实际。但是,您可以对小型数据集执行此操作,但是正如我之前所说,对于大型数据集不可行。要启用Firebase Real-tme数据库的全文本搜索,建议您使用Algolia之类的第三方搜索服务。

与Firebase Realtime数据库不同,Cloud Firestore允许compound queries。您应该看看这个。因此,在Cloud Firestore中允许以下查询,而无需创建组合属性。

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

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

答案 1 :(得分:0)

您已经体验了Firebase的最低功能,即查询。但是,例如,如果您在firebase上上传标题和说明,例如,您可以查询多个值:

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

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

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

onBindViewHolder内的设置值为true,然后一次使用处理程序延迟查询值:

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

希望有帮助。