0

I am trying to implement an SwipeRefreshLayout into my app. What I want to happen is that when the user opens the app initially that the data is retrieved from Firebase without having to pull down the layout so the data refreshes. After that, if the user wants to see new data they have to pull down the layout so the RecyclerView is refreshed with new posts that other users have uploaded.

The problem that I am running into is that when I upload a post from my emulator it pops up on screen automatically on my phone without me having to pull down. That's not what I want. First, initial opening of app data should be retrieved automatically without pull down. After that, every time you want to see new data, if I go to a different fragment and then come back the data shouldn't be refreshed unless I pull down.

The code that I have currently is the following. Can someone tell me why it isn't working the way that I would like it to?

I am relatively sure that it's because of my notifyDataSetChanged(); in my readPosts(); method, but I'm not sure how to fix it... Should I just remove it from readPosts(); and add it to the mSwipeRefreshLayout.post...Runnable?

HomeFragment

public class HomeTabLayoutFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {

    private ProgressBar mProgressBar;
    private PostAdapter mPostAdapter;
    private List<Post> mPostLists;

    private FirebaseAuth mFirebaseAuth;
    private FirebaseUser mFirebaseUser;

    private List<String> mFollowingList;

    private SwipeRefreshLayout mSwipeRefreshLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_home_tab_layout, container, false);

        mFirebaseAuth = FirebaseAuth.getInstance();
        mFirebaseUser = FirebaseAuth.getInstance().getCurrentUser();

        mProgressBar = v.findViewById(R.id.progress_circular);

        RecyclerView recyclerView = v.findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
        linearLayoutManager.setReverseLayout(true);
        linearLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(linearLayoutManager);
        mPostLists = new ArrayList<>();
        mPostAdapter = new PostAdapter(getContext(), mPostLists);
        recyclerView.setAdapter(mPostAdapter);

        mSwipeRefreshLayout = v.findViewById(R.id.refresh);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        mSwipeRefreshLayout.post(() -> {
            mSwipeRefreshLayout.setRefreshing(true);
            readPosts();
        });

        checkIfUserExists();
        checkFollowing();

        return v;
    }

    @Override
    public void onRefresh() {
        readPosts();
    }

    private void checkIfUserExists() {
        if (mFirebaseAuth == null) {
            Intent intent = new Intent(getContext(), RegisterActivity.class);
            startActivity(intent);
        }
    }

    private void checkFollowing() {
        mFollowingList = new ArrayList<>();
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Follow").child(mFirebaseUser.getUid()).child("Following");
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                mFollowingList.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                    mFollowingList.add(snapshot.getKey());
                }

                readPosts();
            }

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

            }
        });
    }

    private void readPosts() {
        mSwipeRefreshLayout.setRefreshing(true);
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Posts");
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                mPostLists.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                    Post post = snapshot.getValue(Post.class);
                    if (post != null && shouldAddPost(post)) {
                        mPostLists.add(post);
                    }
                }

                mPostAdapter.notifyDataSetChanged();
                mProgressBar.setVisibility(View.GONE);
            }

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

            }
        });

        mSwipeRefreshLayout.setRefreshing(false);
    }

    private boolean shouldAddPost(@NotNull Post post) {
        boolean isFollowingPublisher = false;
        for (String id : mFollowingList) {
            if (post.getPublisher().equals(id)) {
                isFollowingPublisher = true;
                break;
            }
        }

        boolean isPublisher = post.getPublisher().equals(mFirebaseUser.getUid());

        return isFollowingPublisher || isPublisher;
    }
}
JMB
  • 313
  • 2
  • 9

1 Answers1

1

That is because you are using a addValueEventListener. In this case a ValueEventListener will get called each time any changes made in this hierarchy.

You should be using addListenerForSingleValueEvent if you want data only once. In other words if you do not want realtime updates for a node then you use addListenerForSingleValueEvent.

->Answer about mSwipeRefreshLayout.setRefreshing(false) positioning inside readPost .

Right now how you added mSwipeRefreshLayout.setRefreshing(true) and mSwipeRefreshLayout.setRefreshing(false) is actually useless . It will call immediately.. What you should be doing is changing the state inside listeners.

private void readPosts() {
    mSwipeRefreshLayout.setRefreshing(true);
    DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Posts");
    reference.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            mPostLists.clear();
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
            Post post = snapshot.getValue(Post.class);
            if (post != null && shouldAddPost(post)) {
                mPostLists.add(post);
            }
        }
            mPostAdapter.notifyDataSetChanged();
            mProgressBar.setVisibility(View.GONE);
            mSwipeRefreshLayout.setRefreshing(false);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            mSwipeRefreshLayout.setRefreshing(false);
        }
    });
ADM
  • 20,406
  • 11
  • 52
  • 83
  • Ah okay man, so in my readPosts(); method change the ValueEventListener to ListenerForSingleValueEvent? – JMB Apr 19 '20 at 04:09
  • Yeah `readPosts` should be using `addListenerForSingleValueEvent` Also `checkFollowing` if this is the same case.. I am not sure what those method does .. Point is if you do not want to listen for changes in database just use `addListenerForSingleValueEvent`. – ADM Apr 19 '20 at 04:11
  • CheckFollowing is the method that I use to see the list of users that you are following. If you follow that person, then their posts should appear on your newsfeed. It's like Instagram. If you follow someone, you see their posts, if not, you don't. Should I modify it there also? – JMB Apr 19 '20 at 04:13
  • Okay In that case it also need a Single event listener `addListenerForSingleValueEvent`. because you do not want realtime uodates.. – ADM Apr 19 '20 at 04:14
  • Okay, great. Works fine. I was wondering one more thing. In my readPosts(); method are the ```mSwipeRefreshListeners``` that I have in the very beginning set to true and very end set to false of the method necessary? – JMB Apr 19 '20 at 04:33
  • Updated the answer. Also see https://stackoverflow.com/questions/33776195/how-to-keep-track-of-listeners-in-firebase-on-android.. – ADM Apr 19 '20 at 04:38
  • Okay got it. I got rid of the two that I had outside the listeners and added them after the ```mProgressBar.setVisibility(View.GONE);``` and onCancelled like you have. Thanks! Seems to be working fine after I changed the ValueEventListener to ListenForSingleValueEvent – JMB Apr 19 '20 at 04:51