1

I am new at android programming. I have an application which can insert into the cloud firestore it also needs to read the data in the Cloud Firestore. It keeps crashing when I am trying to open the activity where I read the data. The logcat gives this error

2021-01-12 21:20:56.733 25524-25524/com.example.ppw1 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.ppw1, PID: 25524
java.lang.IllegalStateException: ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
    at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7080)
    at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
    at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
    at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
    at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
    at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
    at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
    at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
    at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1897)
    at androidx.recyclerview.widget.RecyclerView$1.run(RecyclerView.java:414)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
    at android.view.Choreographer.doCallbacks(Choreographer.java:683)
    at android.view.Choreographer.doFrame(Choreographer.java:616)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

My code is:

package com.example.ppw1;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;

import android.os.Bundle;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;

public class ListActivities extends AppCompatActivity {

    private FirebaseAuth mAuth;
    private FirebaseFirestore db = FirebaseFirestore.getInstance();
    private CollectionReference todoRef = db.collection("users");
    private ToDoAdapter adapter;
    private RecyclerView mFirestoreList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_activities);

        this.setTitle("List Activity");

        mAuth = FirebaseAuth.getInstance();

        setUpRecyclerView();

        mFirestoreList = findViewById(R.id.firestore_list);
    }

    private void setUpRecyclerView()
    {
        Query query = todoRef.whereEqualTo("Email", mAuth.getCurrentUser().getEmail());

        FirestoreRecyclerOptions<ToDoItem> options = new FirestoreRecyclerOptions.Builder<ToDoItem>().setQuery(query,ToDoItem.class).build();


        adapter = new ToDoAdapter(options);

        RecyclerView recyclerView = findViewById(R.id.firestore_list);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        adapter.startListening();
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        adapter.stopListening();
    }
}

My DoToAdapter code which is handling most of the query I am thinking error must be one of those classes but I am not sure.

package com.example.ppw1;

import android.text.format.DateUtils;
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 com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.squareup.okhttp.Request;

public class ToDoAdapter extends FirestoreRecyclerAdapter<ToDoItem, ToDoAdapter.ToDoHolder> {

  // Listener listene r;

    /**
     * Create a new RecyclerView adapter that listens to a Firestore Query.  See {@link
     * FirestoreRecyclerOptions} for configuration options.
     *
     * @param options
     */
    public ToDoAdapter(@NonNull FirestoreRecyclerOptions<ToDoItem> options) {
        super(options);
    }

    @Override
    protected void onBindViewHolder(@NonNull ToDoHolder holder, int position, @NonNull ToDoItem model) {

        holder.title.setText(model.getTitle());
        holder.description.setText(model.getDesc());

       // String timeAgo = (String) DateUtils.getRelativeTimeSpanString(model.getTimeAdded().getSeconds())*1000;
      // holder.dateAdded.setText(timeAgo);


    }

    @NonNull
    @Override
    public ToDoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_to_do_item, parent);

        return new ToDoHolder(v);
    }


    class ToDoHolder extends RecyclerView.ViewHolder {

        TextView title, description, dateAdded;


        public ToDoHolder(@NonNull View itemView) {
            super(itemView);
            title = itemView.findViewById(R.id.todoTitle);
            description = itemView.findViewById(R.id.todoDesc);
           // dateAdded = itemView.findViewById(R.id.dateAdded);
        }
    }

}
Zain
  • 37,492
  • 7
  • 60
  • 84
Abdullah Ergun
  • 63
  • 1
  • 1
  • 8

1 Answers1

6

java.lang.IllegalStateException: ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)

The default value of the attachToRoot is true if the ViewGroup parameter is not null please see the 2-arg inflate method:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

So, you need to use the 3-arg inflate()method to set the third attachToRoot parameter to false when you inflate the item layout within onCreateViewHolder()

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

    return new ToDoHolder(v);
}

attachToRoot Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML.

Zain
  • 37,492
  • 7
  • 60
  • 84