Search code examples
androidfirebase-realtime-databaseandroid-adapterandroid-cardview

Getting a fatal exception while working on firebase database and searchview


I'm trying to use a Searchview with Recylerview and firebase database, i've been following some tutorial and i've followed the video correctly so I don't know why i'm getting an error,i have three classn one is an adapater and a helper and the main one, the error i get is:

2021-05-12 03:16:12.931 31658-31658/com.example.search E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.search, PID: 31658
    com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.search.Deal

in the following line:

list.add(ds.getValue(Deal.class));

this is my main activity:

package com.example.search;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import android.widget.Toast;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    DatabaseReference ref;
    ArrayList<Deal> list;
    RecyclerView recyclerView;
    SearchView searchView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ref = FirebaseDatabase.getInstance().getReference().child("medicines");
        recyclerView = findViewById(R.id.rv);
        searchView = findViewById(R.id.searchview);

    }

    @Override
    protected void onStart() {
        super.onStart();

        if(ref != null){
            ref.addValueEventListener(new ValueEventListener() {
                @NonNull
                @Override
                protected Object clone() throws CloneNotSupportedException {
                    return super.clone();
                }

                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    if(snapshot.exists()){
                        list = new ArrayList<>();
                        for(DataSnapshot ds : snapshot.getChildren()){
                            list.add(ds.getValue(Deal.class));
                        }
                        AdapterClass adapterClass = new AdapterClass(list);
                        recyclerView.setAdapter(adapterClass);

                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
        }
        if (searchView != null){
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    return false;
                }

                @Override
                public boolean onQueryTextChange(String newText) {
                    search(newText);
                    return true;
                }
            });
        }

    }

    private void search(String str) {
        if (!str.equals("")){
            ArrayList<Deal>myList = new ArrayList<>();
            for (Deal object : list){
                if(object.getDisease().toLowerCase().contains(str.toLowerCase())){
                    myList.add(object);
                }
            }
            AdapterClass adapterClass = new AdapterClass(myList);
            recyclerView.setAdapter(adapterClass);
        }

    }

}

and this is my "helper" class which i called deal:

package com.example.search;

public class Deal {
    private String disease, medication;

    public Deal() {
    }

    public Deal(String disease, String medication) {
        this.disease = disease;
        this.medication = medication;
    }

    public String getDisease() {
        return disease;
    }

    public void setDisease(String disease) {
        this.disease = disease;
    }

    public String getMedication() {
        return medication;
    }

    public void setMedication(String medication) {
        this.medication = medication;
    }
}

this is my adapater class:

package com.example.search;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class AdapterClass extends RecyclerView.Adapter<AdapterClass.MyViewHolder> {

    ArrayList<Deal> list;
    public AdapterClass(ArrayList<Deal> list){
        this.list = list;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_holder, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.disease.setText(list.get(position).getDisease());
        holder.medicine.setText(list.get(position).getMedication());
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder{
        TextView disease, medicine;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            disease = itemView.findViewById(R.id.disease);
            medicine =  itemView.findViewById(R.id.medication);
        }
    }

}

and this is my main activity layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <androidx.appcompat.widget.SearchView
        android:id="@+id/searchview"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:padding="10dp"
        android:layout_margin="5dp"
        />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:autofillHints="Search here"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        />
</LinearLayout>

and my card view layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    app:cardElevation="5dp">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <TextView
            android:id="@+id/disease"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="25sp"
            android:textStyle="bold"
            android:padding="10dp"
            android:text="disease_name" />

        <TextView
            android:id="@+id/medication"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="solution"
            android:padding="10dp"
            />
    </LinearLayout>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#000"
        />
</androidx.cardview.widget.CardView>

that's all there is to the whole app so i dont get why the app keeps crashing, this is what my firebase database looks like

{
  "medicines" : {
    "disease" : "maleria",
    "medication" : "aspirin"
  }
}

I was getting different exceptions before and I changed the rules in database and debugged the app and now I'm getting this error been stuck on it for two hours, Honestly no clue, I've already tried checking if I wrote things wrong and if the names I added in my helper(deal)class match with the ones in firebase etc., and they do so I don't know


Solution

  • Since your Deal class defines properties disease and mediation, there seems to be only one Deal object under medicines.

    So with your current data, you shouldn't be using a loop over getChildren in the onDataChange, and simple do:

    public void onDataChange(@NonNull DataSnapshot snapshot) {
        if(snapshot.exists()){
            list = new ArrayList<>();
            list.add(snapshot.getValue(Deal.class));
            AdapterClass adapterClass = new AdapterClass(list);
            recyclerView.setAdapter(adapterClass);
        }
    }