可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am storing data in Firebase storage.
Object Comment
with attribute timestamp
. When I push data from device to Firebase I\'m populating timestamp
with currentTime and store in long
data type.
When I do retrieving the data with firebaseRef.orderByChild(\"timestamp\").limitToLast(15)
result is not sorting how I expected.
I even played around with rules and no result:
{
\"rules\": {
\".read\": true,
\".write\": true,
\".indexOn\": \"streetrate\",
\"streetrate\": {
\".indexOn\": \".value\"
}
}
}
I tried store timestamp
in String
data type, same issue.
回答1:
Firebase can order the items in ascending order by a given property and then returns either the first N items (limitToFirst()
) or the last N items (limitToLast()
). There is no way to indicate that you want the items in descending order.
There are two options to get the behavior you want:
Use a Firebase query to get the correct data, then re-order it client-side
Add a field that has a descending value to the data
For the latter approach, it is common to have a inverted timestamp.
-1 * new Date().getTime();
回答2:
one good solution I find if you are using recycler view to render that data...
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
// And set it to RecyclerView
mRecyclerView.setLayoutManager(mLayoutManager);
it will reverse the data rendering...
private static class ChatMessageViewHolder extends RecyclerView.ViewHolder {
TextView messageText;
TextView nameText;
public ChatMessageViewHolder(View itemView) {
super(itemView);
nameText = (TextView)itemView.findViewById(android.R.id.text1);
messageText = (TextView) itemView.findViewById(android.R.id.text2);
}
}
FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder> adapter;
ref = new Firebase(\"https://<yourapp>.firebaseio.com\");
RecyclerView recycler = (RecyclerView)
findViewById(R.id.messages_recycler);
recycler.setHasFixedSize(true);
//////////////////////////////////////////////////////////
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
recycler.setLayoutManager(mLayoutManager);
/////////////////////////////////////////////////////////
adapter = new FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder>(ChatMessage.class, android.R.layout.two_line_list_item, ChatMessageViewHolder.class, mRef) {
public void populateViewHolder(ChatMessageViewHolder chatMessageViewHolder, ChatMessage chatMessage) {
chatMessageViewHolder.nameText.setText(chatMessage.getName());
chatMessageViewHolder.messageText.setText(chatMessage.getMessage());
}
};
recycler.setAdapter(mAdapter);
回答3:
I don\'t see any option to reverse the data. But One Brute way is to get the data.
List<ModelClass> mList=new ArrayList();
public void onDataChange(DataSnapshot dataSnapshot)
{
mList.clear();
for(DataSnapshot children: dataSnapshot.getChildren()){
ModelClass modelClass=children.getValue(ModelClass.class);
mList.add(modelClass);
}
Collections.reverse(mList);
Adapter.notifyDataSetChanged();
}
回答4:
I have solved problem by extending FirebaseListAdapter and overriding getItem method:
public abstract class ReverseFirebaseListAdapter<T> extends FirebaseListAdapter<T> {
public ReverseFirebaseListAdapter(Activity activity, Class<T> modelClass, int modelLayout, Query ref) {
super(activity, modelClass, modelLayout, ref);
}
public ReverseFirebaseListAdapter(Activity activity, Class<T> modelClass, int modelLayout, DatabaseReference ref) {
super(activity, modelClass, modelLayout, ref);
}
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
}
回答5:
The @Monet_z_Polski approach, based on
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
does have a weird effect on not update FirebaseRecyclerView automatically (PopulateViewHolder is not triggered in realtime changes). So, the best option is use a negative key to index the data.
回答6:
Sort at client side is simple and not require more system resources.
Each data snapshot has previousChildkey field. If you want to desc sorting, imagine previousChildkey is nextChildKey.
Here are my sample:
class LessonFirebaseArray<ObjectModel>{
private ArrayList<ObjectModel> mItems;
...
public LessonFirebaseArray() {
mItems = new ArrayList<>();
}
public int addItem(ObjectModel item, boolean isReverse){
int index;
if (item.getPreviousChildKey() != null) {
index = getIndexForKey(item.getPreviousChildKey());
if (index < 0) {
index = mItems.size();
}else if(index>0 && !isReverse) {
index = index + 1;
}
}else{
index = mItems.size();
}
mItems.add(index, item);
notifyInsertedListeners(index);
return index;
}
private int getIndexForKey(String key) {
int index = 0;
for (ObjectModel snapshot : mItems) {
if (snapshot.getKey().equals(key)) {
return index;
} else {
index++;
}
}
return -1;
}
private void notifyInsertedListeners(int index) {
if (mListener != null) {
mListener.onInserted(index);
}
}
}
回答7:
Swift 3:
let query = firebase.child(YourQueryPath).queryOrdered(byChild: YourQueryChild).queryLimited(toLast: YourLimit)
query.observeSingleEvent(of: .value, with: { (snapshot) in
// Reverse order here to get top **YourLimit** results in descending order
})
回答8:
Sorting child items by TIMESTAMP can be done using android.support.v7.util.SortedList
class post{
private Object time;
public Object getTime() {
return time;
}
public void setTime(Object time) {
this.time = time;
}
...//rest code}
SortedList<post> data;
data = new SortedList<post>(post.class, new SortedList.Callback<post>() {
@Override
public int compare(post o1, post o2) {
Long o1l = Long.parseLong(o1.getTime().toString());
Long o2l = Long.parseLong(o2.getTime().toString());
return o2l.compareTo(o1l);
}......//rest code
ref.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
mSwipeRefreshLayout.setRefreshing(true);
post p=dataSnapshot.getValue(post.class);
data.add(p);
}...// rest code
android.support.v7.util.SortedList
can also be used with RecyclerView