Firebase RecylcerView Adapter Not Getting Accurate

2019-06-11 22:02发布

I am using the Firebase UI and am experiencing a unique issue. When I load the RecyclerView, there are no issues. I click an item on the RecyclerView and get the .push() value of the item that was clicked. It then takes data from that Firebase .push() value, which is stored in the Firebase database, and sends it to another activity. See images below:

enter image description here enter image description here

The second image is the activity that receives data via an intent. When I click back to the RecyclerView, I click "8" again and I am loading a different number (right now it appears to be 1).

Ultimately, I am concerned that I do not have the RecyclerView set up correctly. Here is my code:

Create Poll object (POJO) and write to Firebase:

        mSubmitPollCreation.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            //TODO: Need to check if poll requirements are added, i.e. Question, Answer, ......
            //check if image has been loaded first
            if (resultImageURL == null) {
                Toast.makeText(getApplicationContext(), getResources().getString(R.string.no_image_selected), Toast.LENGTH_LONG).show();
                return;
            }

            //capture answers
            if (mNumberOfPollAnswersCreatedByUser > 5) {
                Toast.makeText(getApplicationContext(), getResources().getText(R.string.poll_answers_greater_than_five), Toast.LENGTH_LONG).show();
                mNumberOfPollAnswersCreatedByUser = 5;
            }
            for (int i = 0; i < mNumberOfPollAnswersCreatedByUser; i++) {
                EditText editText = (EditText) mEditTextAnswerLayout.findViewWithTag(getResources().getString(R.string.created_answer_editText_id) + String.valueOf(i + 1));
                String editTextInputForAnswer = String.valueOf(editText.getText());
                mPollAnswers.add(0, editTextInputForAnswer);                 Toast.makeText(getApplicationContext(),editTextInputForAnswer,Toast.LENGTH_SHORT).show();
            }


            Poll poll = new Poll(mCreatePollQuestion.getText().toString(), resultImageURL, mPollAnswers);
            Map<String, Object> pollMap = poll.toMap();
            final String key = mBaseRef.child("Polls").push().getKey();
            Map<String, Object> childUpdates = new HashMap<String, Object>();
            childUpdates.put("/Polls/" + key, pollMap);

            mBaseRef.updateChildren(childUpdates);
            Collections.reverse(mPollAnswers);
            for (int i = 0; i < mPollAnswers.size(); i++) {
                mBaseRef.child("Polls").child(key).child("answers").child(String.valueOf(i + 1)).updateChildren(poll.answerConvert(mPollAnswers, i));
            }

            Intent toHomeActivity = new Intent(CreateActivity.this, HomeActivity.class);
            toHomeActivity.putExtra("viewpager_position", 2);
            startActivity(toHomeActivity);
        }
    });

Where I read from Firebase and populate a RecyclerView:

public class LiveFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";

private RecyclerView mRecyclerview;
private DatabaseReference mBaseRef;
private DatabaseReference mPollsRef;
private LinearLayoutManager mLayoutManager;
private FloatingActionButton mFloatingActionAdd;

private FirebaseRecyclerAdapter<Poll, PollHolder> mFireAdapter;

private RecyclerView.ItemAnimator mItemAnimator;


// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

private OnFragmentInteractionListener mListener;

public LiveFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment LiveFragment.
 */
// TODO: Rename and change types and number of parameters
public static LiveFragment newInstance(String param1, String param2) {
    LiveFragment fragment = new LiveFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mBaseRef = FirebaseDatabase.getInstance().getReference();
    mPollsRef = mBaseRef.child("Polls");

    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);

    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    final View v = inflater.inflate(R.layout.fragment_new, container, false);
    Log.v("TAG", "ON CREATE CALLED FROM NEW");

    mRecyclerview = (RecyclerView) v.findViewById(R.id.list);
    mRecyclerview.setItemAnimator(new SlideInLeftAnimator());


    mLayoutManager = new LinearLayoutManager(getContext());
    mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    mLayoutManager.setReverseLayout(true);
    mLayoutManager.setStackFromEnd(true);

    mFloatingActionAdd = (FloatingActionButton) getActivity().findViewById(R.id.myFAB);
    mFloatingActionAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent I = new Intent(getActivity().getApplicationContext(), CreateActivity.class);
            startActivity(I);
        }
    });


    mRecyclerview.setLayoutManager(mLayoutManager);
    return v;
}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
    scrollToPosition();
}

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

    mFireAdapter = new FirebaseRecyclerAdapter<Poll, PollHolder>(Poll.class, R.layout.latest_item, PollHolder.class, mBaseRef.child("Polls")) {
        @Override
        protected void populateViewHolder(PollHolder viewHolder, final Poll model, final int position) {
            viewHolder.mPollQuestion.setText(model.getQuestion());
            Picasso.with(getActivity().getApplicationContext())
                    .load(model.getImage_URL())
                    .fit()
                    .into(viewHolder.mPollImage);
            viewHolder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.v("TAG", model.toString());
                    Log.v("TAG","ONCLICKED");
                    Intent toPoll = new Intent(getActivity(), PollHostActivity.class);
                    toPoll.putExtra("POLL_ID", mFireAdapter.getRef(position).getKey());
                    startActivity(toPoll);

                }
            });
            Log.v("TAG", mFireAdapter.getRef(position).getKey());
            Log.v("TAG", String.valueOf(position));
            Log.v("TAG", model.getQuestion());
            Log.v("TAG", model.getImage_URL());
        }
    };

    mRecyclerview.setAdapter(mFireAdapter);
    scrollToPosition();



}

@Override
public void onStop() {
    super.onStop();
    if (mFireAdapter != null) {
        mFireAdapter.cleanup();
    }
}


@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}


public static class PollHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView mPollQuestion;
    ImageView mPollImage;
    View mView;


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

        mPollQuestion = (TextView) itemView.findViewById(R.id.latest_item_question);
        mPollImage = (ImageView) itemView.findViewById(R.id.pollThumbNailImage);
        this.mView = itemView;
        itemView.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        Log.v("TAG", "CLICKED");
    }
}


private void scrollToPosition(){
    mFireAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            super.onItemRangeInserted(positionStart, itemCount);
            int pollCount = mFireAdapter.getItemCount();
            int lastVisiblePosition = mLayoutManager.findLastCompletelyVisibleItemPosition();

            // If the recycler view is initially being loaded or the user is at the bottom of the list, scroll
            // to the bottom of the list to show the newly added message.
            if (lastVisiblePosition == -1 ||
                    (positionStart >= (pollCount - 1) && lastVisiblePosition == (positionStart - 1))) {
                mRecyclerview.scrollToPosition(positionStart);
            }
        }
    });
   }
}

My thoughts:

  1. am I calling mFireAdapter.cleanup() in the right location?

  2. The issue with clicking "8" and seeing "1" does not appear on the first load of the RecyclerView, it only happens when I go from the activity (second image) and the navigate back to the RecyclerView.

  3. I call .setStackFromEnd(true) and .setReverseLayout(true) to reverse the data as it is stored in the FirebaseDatabase, which could be contributing to the issue.

  4. I set up the .setOnClickListener() in the .populateViewHolder() method, and use the following to pass the .push() key in an intent to the next activity:

      toPoll.putExtra("POLL_ID", mFireAdapter.getRef(position).getKey());
    

This method could be getting the incorrect key.

Finally, Firebase Database:

enter image description here

Any help would be appreciated!

1条回答
够拽才男人
2楼-- · 2019-06-11 22:51

You should not use position outside of populateViewHolder as it value may differ. Instead, make your viewHolder final and use viewHolder.getAdapterPosition() to replace it.

查看更多
登录 后发表回答