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