Как мне получить количество элементов в RecyclerView, используя данные firebase?

#android #firebase #firebase-realtime-database #android-recyclerview #android-cardview

#Android #firebase #firebase-realtime-database #android-recyclerview #android-cardview

Вопрос:

Я создаю RecyclerView с серией карточек внутри. Моя конечная цель — иметь возможность изменять текст внутри отдельного CardView в activity из-за времени вызовов базы данных firebase. Мой вопрос прямо сейчас заключается в том, как получить количество элементов в RecyclerView?

Я знаю, что большинство из них будут ссылаться на метод Adapter.getItemCount() . Однако на данный момент это возвращает только ноль, поскольку адаптер, похоже, еще не создан. Я считаю, что этот вопрос больше соответствует срокам выполнения кода.

Класс activity:

 package com.cmsc355.forfit;

import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.cmsc355.forfit.util.exerciseAdapterClass;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
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;
import java.util.HashMap;

public class ChallengeView extends AppCompatActivity {

    public static Context context;
    public static String cCESnapshot;

    //Variables
    String team;
    HashMap<String, String> currChallenges;
    ArrayList<String> subAthletes;
    ArrayList<String> exerciseList;
    ArrayList<String> teamMem;

    //System
    private Intent intent;
    public static String cName;

    //XML
    private TextView name;
    private TextView startDateTV;
    private TextView endDateTV;
    private TextView description;
    private Button bSubscribe;
    private Button bDropout;

    private ProgressBar difficulty;

    //Exercise List
    private RecyclerView exerciseRecyclerView;
    private RecyclerView.Adapter exerciseAdapter;
    private RecyclerView.LayoutManager exerciselayoutManager;

    //Database
    DatabaseReference databaseReferenceChallenge;
    DatabaseReference databaseReferenceAthlete;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //Initial setup of activity
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_challenge_view);

        ChallengeView.context = getApplicationContext();

        //variable list
        currChallenges = new HashMap<>();
        subAthletes = new ArrayList<>();
        exerciseList = new ArrayList<>();
        teamMem = new ArrayList<>();

        //system references
        intent = getIntent();
        cName = intent.getStringExtra("name");
        //cCESnapshot = intent.getStringExtra("snapshot");
        //System.out.println(cCESnapshot);

        //Authentication references
        FirebaseAuth mAuth = FirebaseAuth.getInstance();
        FirebaseUser user = mAuth.getCurrentUser();

        final String uid = user.getUid();

        //XML references
        name = findViewById(R.id.ChallengeName);
        startDateTV = findViewById(R.id.DurationTextStart);
        endDateTV = findViewById(R.id.DurationTextEnd);
        description = findViewById(R.id.DescriptionText);
        difficulty = findViewById(R.id.difficultyBar);

        bSubscribe = findViewById(R.id.BSignUp);
        bDropout = findViewById(R.id.CV_DropOut);

        //Exercise List
        exerciseRecyclerView = findViewById(R.id.ExerciseView);
        exerciseRecyclerView.setHasFixedSize(true);

        exerciselayoutManager = new LinearLayoutManager(this);
        exerciseRecyclerView.setLayoutManager(exerciselayoutManager);

        exerciseAdapter = new exerciseAdapterClass(exerciseList);
        exerciseRecyclerView.setAdapter(exerciseAdapter);
        exerciseAdapter.notifyDataSetChanged();


        //database references
        databaseReferenceChallenge = FirebaseDatabase.getInstance().getReference("Challenges");
        databaseReferenceAthlete = FirebaseDatabase.getInstance().getReference("Athlete Users");



        //Initial population of views and variables
        databaseReferenceChallenge.addValueEventListener(new ValueEventListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                DataSnapshot da = dataSnapshot.child(cName);

                String dateStart = da.child("StartDate").child("day").getValue()   "/"   da.child("StartDate").child("month").getValue()  "/"   da.child("StartDate").child("year").getValue();
                String dateEnd = da.child("EndDate").child("day").getValue()   "/"   da.child("EndDate").child("month").getValue()  "/"   da.child("EndDate").child("year").getValue();


                long diff = (long)da.child("difficulty").getValue();
                int tDifficulty = (int)diff;

                name.setText((String)da.child("name").getValue());
                startDateTV.setText(dateStart);
                endDateTV.setText(dateEnd);
                description.setText((String)da.child("description").getValue());
                difficulty.setMin(1);
                difficulty.setMax(5);
                difficulty.setProgress(tDifficulty);


                for(DataSnapshot ex : da.child("exercises").getChildren()){
                    exerciseList.add((String)ex.getValue());
                }

            }

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

            }
        });

        //***************************************************************************************************************************************\
        //This should be grabbing all the challenges that the athlete is currently subscribed to.
        databaseReferenceAthlete.addListenerForSingleValueEvent(new ValueEventListener(){
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                DataSnapshot dataSnapshot1 = dataSnapshot.child(uid).child("currChallenges");
                HashMap<String, String> currChallengesT = (HashMap<String, String>) dataSnapshot1.getValue();
                currChallenges.clear();
                if(currChallengesT != null) {
                    currChallenges.putAll(currChallengesT);
                    if(currChallenges.containsKey(cName)) {
                        bSubscribe.setVisibility(View.GONE);
                        bDropout.setVisibility(View.VISIBLE);
                    }
                    else{
                        bSubscribe.setVisibility(View.VISIBLE);
                        bDropout.setVisibility(View.GONE);
                    }
                }
                else{
                    bSubscribe.setVisibility(View.VISIBLE);
                    bDropout.setVisibility(View.GONE);
                }
            }
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {}
        });
        //***************************************************************************************************************************************\

        //***************************************************************************************************************************************\
        //This should be grabbing all the athletes subscribed to the challenge.
        databaseReferenceChallenge.addListenerForSingleValueEvent(new ValueEventListener(){
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                DataSnapshot dataSnapshot1 = dataSnapshot.child(cName).child("subscribedAthletes");
                ArrayList<String> subAthletesT = (ArrayList<String>) dataSnapshot1.getValue();
                if(subAthletesT != null) {
                    subAthletes.addAll(subAthletesT);
                }
            }
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {}
        });
        //***************************************************************************************************************************************\

        databaseReferenceAthlete.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                DataSnapshot dataSnapshot1 = dataSnapshot.child(uid).child("currChallenges").child(cName).child("team");
                team = (String) dataSnapshot1.getValue();
            }

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

            }
        });
    }

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


        //This is where I try to call the Recycler View.

        System.out.println(exerciseList.size());

        for(int i = 0; i < exerciseAdapter.getItemCount(); i   ){
            System.out.println("Inside for loop: "   i);
            CardView thing = (CardView) exerciselayoutManager.getChildAt(i);
            exerciseAdapterClass.exerciseViewHolder holder = (exerciseAdapterClass.exerciseViewHolder) exerciseRecyclerView.getChildViewHolder(thing);
            System.out.println("nn==============================================================n"   holder.amount.getText().toString()  
                    "n==============================================================");
        }

    }

    public static Context getAppContext() {
        return ChallengeView.context;
    }

    /*
    Calls for the transfer to the challenge signup activity
     */
    public void Subscribe(View view){
        Intent intent = new Intent (this, ChallengeSignUp.class);
        intent.putExtra("name", cName);
        startActivity(intent);

    }
}

  

Класс адаптера:

 package com.cmsc355.forfit.util;

import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.cmsc355.forfit.ChallengeView;
import com.cmsc355.forfit.R;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
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 exerciseAdapterClass extends RecyclerView.Adapter<exerciseAdapterClass.exerciseViewHolder>{

    ArrayList<String> exerciseList;

    public static class exerciseViewHolder extends RecyclerView.ViewHolder {
        public CardView cardView;
        public TextView exerciseName;
        public TextView amount;
        public EditText inputAmount;
        public Button bEnter;

        DatabaseReference databaseReferenceChallenge;
        DatabaseReference databaseReferenceAthlete;

        int currDone;



        public exerciseViewHolder(View itemView) {
            super(itemView);

            //Variables
            currDone = 0;

            //Authentication
            FirebaseAuth mAuth = FirebaseAuth.getInstance();
            FirebaseUser user = mAuth.getCurrentUser();
            final String uid = user.getUid();

            //Database Reference
            databaseReferenceChallenge = FirebaseDatabase.getInstance().getReference("Challenges");
            databaseReferenceAthlete = FirebaseDatabase.getInstance().getReference("Athlete Users");

            //XML
            cardView = itemView.findViewById(R.id.cv_cardView);
            exerciseName = itemView.findViewById(R.id.cv_exerciseName);
            amount = itemView.findViewById(R.id.cv_amount);
            inputAmount = itemView.findViewById(R.id.cv_input);
            bEnter = itemView.findViewById(R.id.cv_button);

            bEnter.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(!(inputAmount.getText().toString().trim().length() == 0)){
                        int input = Integer.parseInt(inputAmount.getText().toString());
                        final String cName = ChallengeView.cName;

                        databaseReferenceAthlete.addValueEventListener(new ValueEventListener() {
                            @Override
                            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                                try{
                                    DataSnapshot snapshot = dataSnapshot.child(uid).child("currChallenges").child(cName).child(exerciseName.getText().toString());
                                    currDone = (int)((long)snapshot.getValue());
                                }
                                catch(Exception e){
                                    e.printStackTrace();
                                }
                            }

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

                        currDone  = input;
                        databaseReferenceAthlete.child(uid).child("currChallenges").child(cName).child(exerciseName.getText().toString()).setValue(currDone);

                    }
                    else{
                        Toast.makeText(ChallengeView.getAppContext(), "Nothing in there.", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }

    public exerciseAdapterClass(ArrayList<String> inputList){
        exerciseList = inputList;
    }

    @Override
    public int getItemCount() {

        return exerciseList.size();
    }

    @Override
    public exerciseViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.cv_card, viewGroup, false);
        exerciseViewHolder pvh = new exerciseViewHolder(v);
        return pvh;
    }

    @Override
    public void onBindViewHolder(final exerciseViewHolder holder, final int i) {
        holder.setIsRecyclable(false);

        String s1 = exerciseList.get(i);

        //Possible error if the name contains "Amount"
        final String name = s1.substring(0, s1.indexOf("Amount")-1); //first section of the string to give the name.

        String s2 = s1.substring(s1.indexOf(": ")); //cuts of the front of the string and puts to a new substring.

        String a = s2.substring(s2.indexOf(' '), s2.indexOf("n")); //cuts the part after the : but before the n
        a = a.trim(); //trims the inevitable white space
        final String units = a.substring(a.indexOf(' ')); //gets the units off the string
        a = a.substring(0, a.indexOf(' ')); //cuts off the units
        final int amount = Integer.parseInt(a); //parse to use as a number

        String s3 = s2.substring(s2.indexOf("n")); //cuts to the date and new string
        s3 = s3.substring(8); //removes the date tag

        String y = s3.substring(0, s3.indexOf('/')); //cuts year into new string
        final int year = Integer.parseInt(y); //parse year to use as a number

        s3 = s3.substring(s3.indexOf('/')   1); //cuts year off

        String d = s3.substring(0, s3.indexOf('/')); //cuts day into new string
        final int day = Integer.parseInt(d); //parse day

        s3 = s3.substring(s3.indexOf('/')   1); //cuts day off
        final int month = Integer.parseInt(s3); //parses month

        /*DatabaseReference databaseReferenceAthlete = FirebaseDatabase.getInstance().getReference("Athlete Users");
        databaseReferenceAthlete.addValueEventListener(new ValueEventListener() {

            FirebaseAuth mAuth = FirebaseAuth.getInstance();
            FirebaseUser user = mAuth.getCurrentUser();
            final String uid = user.getUid();

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                DataSnapshot snapshot = dataSnapshot.child(uid).child("currChallenges").child(ChallengeView.cName).child(name);
                try{
                    int val = ((int)((long)snapshot.getValue()));


                    int printVal = Math.max(0, amount - val);



                }
                catch(Exception e){}
            }

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

            }
        });*/
        holder.amount.setText("0"   units);
        holder.exerciseName.setText(name);
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }
}
  

На данный момент, когда я пытаюсь вызвать что-либо, ссылающееся на RecyclerView, оно возвращает либо 0, либо null. Я думаю, что код для создания RecyclerView еще не запущен.

Ответ №1:

Что вы сделали: в классе адаптера вы пытаетесь получить данные firebase. К тому времени, когда он возвращает данные, вызывается конструктор, и размер списка exerciseList равен нулю. И еще одна вещь, на которую следует обратить внимание, это то, что вы упомянули вызов firebase (который работает в фоновом режиме) в ViewHolder классе.

Лучший способ сделать это: сначала вы получаете данные из firebase вне адаптера, а затем устанавливаете адаптер. Например, MainActivity выполните фоновое задание (для извлечения данных из Firebase), а затем после успешного извлечения установите адаптер следующим образом

 exerciseAdapterClass adapter = new Adapter (exerciseList);
recyclerView.setAdapter(adapter);
  

Если вы хотите уведомить представление recycler о том, произошли ли какие-либо изменения в данных firebase, вы можете сделать это, как показано ниже:

Получить измененный список ( exerciseList ) Или измененный элемент ( String ) из firebase с помощью

 databaseReferenceAthlete.addValueEventListener 
  

Или

 databaseReferenceAthlete.addChildEventListener
  

и затем

 adapter.update(exerciseList);
adapter.notifyDatasetChanged;
  

Или

 adapter.update(newString);
adapter.notifyItemChanged(position)
  

* Примечание: вы должны настроить метод обновления в классе адаптера

Пример: адаптер для обновления списка

 public class NoteListAdapter extends RecyclerView.Adapter<NoteListAdapter.NoteViewHolder> {

private List<String> list;

public NoteListAdapter(List<String> list) {
    this.list = list;
}

public void update(List<String> list){
    this.list = list;
}

@NonNull
@Override
public NoteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
    Context context = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(context);
    View noteView = inflater.inflate(R.layout.item_note, parent, false);

    return new NoteViewHolder(noteView);
}

@Override
public void onBindViewHolder(@NonNull NoteViewHolder holder, int i) {
    String itemString = list.get(i);
    holder.textView.setText(itemString);
}

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

public class NoteViewHolder extends RecyclerView.ViewHolder{
    private TextView textView;

    public NoteViewHolder(@NonNull View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.text_rv);
    }
}
}
  

в MainActivity:

 public class NotesActivity extends AppCompatActivity implements NotesContract.View{

private TextView textView;
private Button add;
private NotesContract.UserActionsListener mActionsListener;
private NoteRepository repository;

private RecyclerView recyclerView;
private NoteListAdapter adapter;
List<String> list = new ArrayList<>();

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

    textView = findViewById(R.id.text_view);
    add = findViewById(R.id.button);
    repository = new NoteRepository();
    recyclerView = findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    adapter = new NoteListAdapter(list);
    recyclerView.setAdapter(adapter);



    mActionsListener = new NotePresenter(repository,this);
    add.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            mActionsListener.loadNotes("hello");
        }
    });
}

@Override
public void showAddNote(List<String> data) {
    String line = "";
    for(String s:data){
        line = line.concat(s);

    }
    textView.setText(line);
}

@Override
public void showRecViewNote(List<String> data) {
    adapter.update(data);
    adapter.notifyDataSetChanged();


}
}
  

Посмотрите, как настроено представление recycler

 recyclerView = findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    adapter = new NoteListAdapter(list);
    recyclerView.setAdapter(adapter);
  

и как это уведомляется

 public void showRecViewNote(List<String> data) {
    adapter.update(data);
    adapter.notifyDataSetChanged();


}
  

Комментарии:

1. Единственное место, из которого я вызываю firebase в адаптере, находится в onButtonClick. Хотя это может помочь с другой проблемой. Однако, как я могу настроить функцию «обновить»? На данный момент все, что я делаю, это обновляю ArrayList<String> . Есть ли какой-нибудь способ снова вызвать методы?

2. в методе onBindViewHolder класса adapter вы также можете вызвать firebase, например holder.button.setOnClickListner() . В классе адаптера укажите метод update(exerciseList), и там вы можете поменять старый список новым списком.

3. Уверен, что вы имеете в виду закомментированный фрагмент кода. Я оставил это там, поэтому мне не нужно переосмысливать свой путь через вызов. Он не запускается.