Je construis une application qui va montrer des vidéos stockées sur firebase. La liste des vidéos doit être paginée pour aller chercher les 20 dernières vidéos à la fois.
Voici le code que je pensais fonctionnerait
private void getVideos() {
Query videosQuery = FirebaseUtil.getVideosRef();
videosQuery.startAt(0);
videosQuery.endAt(1);
ChildEventListener videosChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String date = dataSnapshot.getKey();
String temp = date;
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.d(tag, "database error");
}
};
ValueEventListener videoValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String date = dataSnapshot.getKey();
String temp = date;
long count = dataSnapshot.getChildrenCount();
String value = dataSnapshot.getValue().toString();
temp = value;
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.d(tag, "database error");
}
};
// videosQuery.addChildEventListener(videosChildEventListener);
videosQuery.addValueEventListener(videoValueEventListener);
}
Mais le code ci-dessus récupère la liste complète des vidéos au lieu de vidéos limitées. Comment peut-on mettre en œuvre la pagination?.
Vous trouverez ci-dessous le code que j'utilise pour la pagination, qui affiche en premier le dernier nœud.
public void getImages() {
Query imagesQuery = FirebaseDatabase.getInstance().getReference().child("englishDps").child(mChildName).orderByKey().limitToLast(21);
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Image image = dataSnapshot.getValue(Image.class);
image.setNodeKey(dataSnapshot.getKey());
mTempImages.add(image);
if (mTempImages.size() == 21) {
mLastKey = mTempImages.get(0).getNodeKey();
Collections.reverse(mTempImages);
mTempImages.remove(mTempImages.size() - 1);
mImages.addAll(mTempImages);
setAdapter();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
if (isAdded()) {
Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
}
}
};
imagesQuery.addChildEventListener(childEventListener);
}
@Override
public void getMoreImages() {
if (!mGettingMoreImages) {
mGettingMoreImages = true;
Query imagesQuery = FirebaseDatabase.getInstance().getReference("englishDps").child(mChildName).orderByKey().endAt(mLastKey).limitToLast(21);
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Image image = dataSnapshot.getValue(Image.class);
image.setNodeKey(dataSnapshot.getKey());
mMoreImages.add(image);
if (mMoreImages.size() == 21) {
mLastKey = mMoreImages.get(0).getNodeKey();
Collections.reverse(mMoreImages);
mMoreImages.remove(mMoreImages.size() - 1);
mImages.addAll(mMoreImages);
mMoreImages.clear();
mGettingMoreImages = false;
mImagesAdapter.notifyDataSetChanged();
return;
}
if (mLastKey.equalsIgnoreCase(image.getNodeKey())) {
Collections.reverse(mMoreImages);
mImages.addAll(mMoreImages);
mMoreImages.clear();
mGettingMoreImages = false;
mImagesAdapter.onNoMoreImages();
;
mImagesAdapter.notifyDataSetChanged();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
if (isAdded()) {
Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
}
}
};
imagesQuery.addChildEventListener(childEventListener);
}
}
Vous souhaitez utiliser les méthodes limitToFirst/limitToLast pour extraire un nombre limité de résultats.
videosQuery.orderByKey().limitToFirst(20)
https://www.firebase.com/docs/web/api/query/limittofirst.html
Vous devriez vraiment envisager de changer la convention de nommage de vos vidéos pour inclure les 0 premiers (par exemple, vidéo01, vidéo02 ... vidéo10, vidéo11), car le code ci-dessus les affichera exactement tels que vous les avez décrits ci-dessus (ce qui, je suppose, est en panne?)
Si vous ajoutez les vidéos via Java, vous pouvez également laisser firebase créer les identifiants uniques via Push (). Les informations uniques sont générées de manière à pouvoir être classées de manière chronilogique, ce qui semble correspondre à votre besoin de saisir les vidéos les plus récentes (récemment ajoutées?).
mPageEndOffset = 0;
mPageLimit = 10;
mPageEndOffset += mPageLimit;
deviceListQuery = mDatabase.child("users")
.orderByChild("id").limitToFirst(mPageLimit).startAt(mPageEndOffset);
deviceListQuery.addValueEventListener(YourActivity.this);
J'ai méthode suivante pour paginer à travers un nœud de base de données en temps réel firebase:
private void getUsers(String nodeId) {
Query query;
if (nodeId == null)
query = FirebaseDatabase.getInstance().getReference()
.child(Consts.FIREBASE_DATABASE_LOCATION_USERS)
.orderByKey()
.limitToFirst(mPostsPerPage);
else
query = FirebaseDatabase.getInstance().getReference()
.child(Consts.FIREBASE_DATABASE_LOCATION_USERS)
.orderByKey()
.startAt(nodeId)
.limitToFirst(mPostsPerPage);
query.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
UserModel user;
List<UserModel> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
userModels.add(userSnapshot.getValue(UserModel.class));
}
mAdapter.addAll(userModels);
mIsLoading = false;
}
@Override
public void onCancelled(DatabaseError databaseError) {
mIsLoading = false;
}
});
}
Chaque fois que j'atteins le bas des données paginées, j'appelle la fonction getUsers(mAdapter.getLastItemId());
, puis le jeu d'enregistrements suivant s'affiche.
J'ai écrit un guide complet avec un exemple d'application open source que vous pouvez consulter à l'adresse suivante: https://blog.shajeelafzal.com/2017/12/13/firebase-realtime-database-pagination-guide-using-recyclerview/
Puisque cette question concernant l’implémentation de Pagination dans une requête sur Firestore est marquée comme une copie de cette question, je vais y répondre ici.
Paginer une requête sur Android Firestore
Query query = db.collection("cities")
.orderBy("population")
.limit(25);
Query next = query;
private void loadCities() {
query = next;
query.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// Get the last visible document
DocumentSnapshot lastVisible =
documentSnapshots.getDocuments()
.get(documentSnapshots.size() -1);
// Construct a new query starting at this document,
// get the next 25 cities.
next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
}
});
}
Appelez maintenant la méthode loadCities()
chaque fois que vous devez charger plus de villes.
La bibliothèque de pagination Android peut être utilisée pour implémenter la pagination des données extraites de la base de données Firebase. Les données sont affichées dans la vue du recycleur et le composant de pagination récupère les pages en réponse aux événements de défilement de l'utilisateur.
La source de données de pagination appelle votre objet DAO firebase en transmettant des paramètres de requête pour la page à afficher et les résultats sont renvoyés au composant de pagination à l’aide du rappel fourni.
Voici un exemple complet pour référence http://www.zoftino.com/firebase-pagination-using-Android-paging-library
Voici comment j'ai implémenté la pagination à partir de la base de données firebase. Considérons un cas si nous avons 100 messages. Donc, je charge d’abord les 20 derniers messages à partir de firebase, soit 81 à 100. Puis, lorsque je fais défiler la page vers le haut, j’appelle la fonction getMoreMessages()
pour charger les 20 prochains messages (61 à 80, etc.).
public class ChatActivity extends Activity {
String chat_id = "";
long mTotalChildren = 0;
boolean loading = false;
ChildEventListener childEventListenerMain, childEventListenerPager;
ChatActivity mContext = ChatActivity.this;
MessageAdapter messageAdapter;
@BindView(R.id.pb_messages)
ProgressBar pb_messages;
@BindView(R.id.ll_audio)
LinearLayout llAudio;
@BindView(R.id.tv_record_time)
AppCompatTextView tvRecordTime;
@BindView(R.id.tv_cancel)
AppCompatTextView tvCancel;
@BindView(R.id.iv_send)
AppCompatImageView ivSend;
@BindView(R.id.iv_record)
AppCompatImageView ivRecord;
@BindView(R.id.ab_layout)
AppBarLayout abLayout;
@BindView(R.id.messages)
RecyclerView rvMessages;
@BindView(R.id.iv_chat_icon)
SimpleDraweeView ivChatIcon;
@BindView(R.id.iv_camera)
AppCompatImageView ivCamera;
@BindView(R.id.iv_gallery)
AppCompatImageView ivGallery;
@BindView(R.id.message_input)
AppCompatEditText messageInput;
@BindView(R.id.tv_send)
AppCompatTextView tvSend;
@BindView(R.id.toolbar_title)
AppCompatTextView toolbarTitle;
@BindView(R.id.toolbar_status)
AppCompatTextView toolbarStatus;
@BindView(R.id.ll_send)
LinearLayout llSend;
int categoryId, senderId, receiverId, offerId;
String mLastKey;
LinearLayoutManager layoutManager;
private ArrayList<MessageModel> messageArrayList = new ArrayList<>();
private ArrayList<MessageModel> tempMessageArrayList = new ArrayList<>();
@Override
public int getLayoutId() {
return R.layout.activity_chat;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
messageAdapter = new MessageAdapter(mContext, messageArrayList) {
};
layoutManager = new LinearLayoutManager(mContext);
rvMessages.setLayoutManager(layoutManager);
rvMessages.setItemAnimator(new DefaultItemAnimator());
rvMessages.setAdapter(messageAdapter);
rvMessages.setHasFixedSize(true);
rvMessages.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (messageArrayList.size() >= 20 &&
!loading && layoutManager.findFirstVisibleItemPosition() == 0 && messageArrayList.size() < mTotalChildren) {
loading = true;
getMoreMessages();
}
}
});
messageAdapter.notifyDataSetChanged();
//used to scroll up recyclerview when keyboard pops up
rvMessages.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (bottom < oldBottom) {
rvMessages.postDelayed(new Runnable() {
@Override
public void run() {
rvMessages.scrollToPosition(messageArrayList.size() - 1);
}
}, 100);
}
}
});
loading = true;
getMessages();
}
public void getMessages() {
FirebaseDatabase.getInstance().getReference().child(pathtomsgs).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.e("childrenCount", String.valueOf(+dataSnapshot.getChildrenCount()));
mTotalChildren = dataSnapshot.getChildrenCount();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
Query messageQuery = FirebaseDatabase.getInstance().getReference().child(pathtomsgs).limitToLast(20);
childEventListenerMain = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
loading = true;
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
messageModel.chat_id = chat_id;
messageModel.message_id = dataSnapshot.getKey();
messageArrayList.add(messageModel);
messageAdapter.notifyDataSetChanged();
mLastKey = messageArrayList.get(0).message_id;
rvMessages.scrollToPosition(messageArrayList.size() - 1);
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext, "Problem loading more images...", Toast.LENGTH_LONG).show();
}
};
messageQuery.addChildEventListener(childEventListenerMain);
ValueEventListener messageChildSINGLEValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
pb_messages.setVisibility(View.GONE);
System.out.println("We're done loading messages " + dataSnapshot.getChildrenCount() + " items");
loading = false;
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
messageQuery.addListenerForSingleValueEvent(messageChildSINGLEValueEventListener);
}
public void getMoreMessages() {
tempMessageArrayList.clear();
Query messageQuery = FirebaseDatabase.getInstance().getReference().child(pathtomsgs).orderByKey().endAt(mLastKey).limitToLast(20);
childEventListenerPager = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
loading = true;
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
messageModel.chat_id = chat_id;
messageModel.message_id = dataSnapshot.getKey();
tempMessageArrayList.add(messageModel);
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext, "Problem loading more images...", Toast.LENGTH_LONG).show();
}
};
messageQuery.addChildEventListener(childEventListenerPager);
ValueEventListener messageChildSINGLEValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("We're done loading messages " + dataSnapshot.getChildrenCount() + " items");
tempMessageArrayList.remove(tempMessageArrayList.size() - 1);
messageArrayList.addAll(0, tempMessageArrayList);
mLastKey = messageArrayList.get(0).message_id;
messageAdapter.notifyDataSetChanged();
//rvMessages.scrollToPosition(20);
layoutManager.scrollToPositionWithOffset(19, 0);
loading = false;
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
messageQuery.addListenerForSingleValueEvent(messageChildSINGLEValueEventListener);
}
@Override
protected void onDestroy() {
FirebaseDatabase.getInstance().getReference().child(pathtomsgs).removeEventListener(childEventListenerPager);
FirebaseDatabase.getInstance().getReference().child(pathtomsgs).removeEventListener(childEventListenerMain);
super.onDestroy();
}
}
les réponses acceptées ne fonctionnent pas si elles sont inférieures au max. itmes (21) in database ..__ Ceci est ma solution basée sur la réponse acceptée:
0) définir les variables
private String lastMessageKey;
private int totalItemCount;
private int lastVisibleItem;
private boolean isLoadingMoreFollowers = false;
private boolean hasMoreItems = true;
private boolean hasShownNoMoreItemsToast = false;
private boolean initialLoad = true;
private final int MAX_LOAD_ITEMS = 11;
private final int VISIBLE_TRESHOLD = 1;
1) définir un auditeur:
private void setMessageListener() {
if (childEventListener == null) {
mmessageArrayList.clear();
final ArrayList<Mmessage> tempMmessages = new ArrayList<>();
query = mDatabaseInstace.getReference().child(chat1).child(F.CHATS).child(F.MESSAGES).orderByKey().limitToLast(MAX_LOAD_ITEMS-1);
childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
Log.d(TAG, "onChildAdded: -----------------> " + dataSnapshot);
Log.d(TAG, "onChildAdded: -----------------> " + s);
tempMmessages.add(dataSnapshot.getValue(Mmessage.class));
preloadMessagePics(tempMmessages);
if (initialLoad) {
lastMessageKey = tempMmessages.get(0).getMessagePushKey();
initialLoad = false;
}
mmessageArrayList.add(tempMmessages.size()-1, tempMmessages.get(0));
messageAdapter.notifyDataSetChanged();
tempMmessages.clear();
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
Log.d(TAG, "onChildChanged: --------------------------------->");
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved: ---------------------------------->");
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
Log.d(TAG, "onChildMoved: ------------------------------------>");
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.d(TAG, "onCancelled: ------------------------------------->");
}
};
query.addChildEventListener(childEventListener);
}
}
2) définir la charge plus auditeur:
private void setLoadMoreListener(){
setup.RV_messages.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoadingMoreFollowers && totalItemCount <= (lastVisibleItem+VISIBLE_TRESHOLD) && (totalItemCount >= MAX_LOAD_ITEMS-1)){
if (hasMoreItems) {
getMoreMessages();
Toast.makeText(homeActivity, "load more items", Toast.LENGTH_SHORT).show();
}else {
if (!hasShownNoMoreItemsToast) {
Toast.makeText(homeActivity, "has no more items", Toast.LENGTH_SHORT).show();
hasShownNoMoreItemsToast = true;
}
}
}
}
});
}
3) obtenir plus d'articles:
private void getMoreMessages(){
final ArrayList<Mmessage> tempMmessages = new ArrayList<>();
isLoadingMoreFollowers = true;
loadMoreQuery = mDatabaseInstace.getReference().child(chat1).child(F.CHATS).child(F.MESSAGES).orderByKey().endAt(lastMessageKey).limitToLast(MAX_LOAD_ITEMS);
loadMoreChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
tempMmessages.add(dataSnapshot.getValue(Mmessage.class));
preloadMessagePics(tempMmessages);
if (tempMmessages.size() == MAX_LOAD_ITEMS){
lastMessageKey = tempMmessages.get(0).getMessagePushKey();
Collections.reverse(tempMmessages);
tempMmessages.remove(0);
mmessageArrayList.addAll(tempMmessages);
isLoadingMoreFollowers = false;
messageAdapter.notifyDataSetChanged();
tempMmessages.clear();
return;
}
if (lastMessageKey.equalsIgnoreCase(tempMmessages.get(tempMmessages.size()-1).getMessagePushKey())){
Collections.reverse(tempMmessages);
tempMmessages.remove(0);
mmessageArrayList.addAll(tempMmessages);
isLoadingMoreFollowers = false;
hasMoreItems = false;
messageAdapter.notifyDataSetChanged();
tempMmessages.clear();
}
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
};
loadMoreQuery.addChildEventListener(loadMoreChildEventListener);
}
s'amuser!!