Android 中的 Firebase 数据描述排序
Firebase Data Desc Sorting in Android
我正在将数据存储在 Firebase 存储中。
具有属性 timestamp
的对象 Comment
。当我将数据从设备推送到 Firebase 时,我用 currentTime 填充 timestamp
并存储在 long
数据类型中。
当我使用 firebaseRef.orderByChild("timestamp").limitToLast(15)
检索数据时,结果并未按照我的预期进行排序。
我什至玩过规则但没有结果:
{
"rules": {
".read": true,
".write": true,
".indexOn": "streetrate",
"streetrate": {
".indexOn": ".value"
}
}
}
我尝试在 String
数据类型中存储 timestamp
,同样的问题。
Firebase 可以按给定的 属性 对项目进行升序排序,然后 returns 前 N 个项目 (limitToFirst()
) 或最后 N 个项目 (limitToLast()
).无法表明您希望项目按降序排列。
有两个选项可以获得您想要的行为:
使用 Firebase 查询获取正确的数据,然后在客户端重新排序
向数据添加一个具有降序值的字段
对于后一种方法,通常有一个倒置的时间戳。
-1 * new Date().getTime();
我已经通过扩展 FirebaseListAdapter 和覆盖 getItem 方法解决了问题:
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));
}
}
@Monet_z_Polski 方法,基于
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
对于不自动更新 FirebaseRecyclerView 确实有奇怪的影响(实时更改不会触发 PopulateViewHolder)。所以,最好的选择是使用负键索引数据。
在客户端排序很简单,不需要更多的系统资源。
每个数据快照都有 previousChildkey 字段。如果要 desc 排序,想象 previousChildkey 是 nextChildKey。
这是我的样本:
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);
}
}
}
如果您使用回收器视图来呈现该数据,我发现了一个很好的解决方案...
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
// And set it to RecyclerView
mRecyclerView.setLayoutManager(mLayoutManager);
它将反转数据渲染...
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);
我没有看到任何反转数据的选项。但是一种粗暴的方法是获取数据。
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();
}
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
})
可以使用 android.support.v7.util.SortedList
按 TIMESTAMP 对子项进行排序
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
也可以与 RecyclerView
一起使用
如果您在 Web 上执行此操作,则可以将值推送到数组中,然后以相反的顺序打印存储的值。
var a=[]; //declaring an array a.
var num=snapshot.numChildren(); //storing number of children in var num.
a.push(snapshot.val()); // pushing data in the array.
if (a.length==num){ //checking if length of array is same as number of children.
a.reverse(); //reversing the array elements.
for(i=0; i<num; i++){
a[i].name;//this will sort the data in descending order.
}
}
添加一列,即时间戳,值为 (-1*System.currentTimeMillis())
并在获取数据时使用 orderByChild("timestamp").limitToFirst(15)
或 orderByChild("timestamp").limitToLast(15)
根据您的要求。
以排序的方式获取数据是一种聪明的方式,因为 firebase 没有降序规则。
很简单,使用-1,-2,-3等在firebase中存储数据database.Now数据会在recyclerView中倒序显示
-3
-2
-1
我发现目前的firebase版本支持降序排序:
citiesRef.orderBy("name", "desc").limit(3)
https://firebase.google.com/docs/firestore/query-data/order-limit-data
希望对您有所帮助
您可以简单地反转您正在使用的列表(ListView 或 RecyclerView)。
基于 Himanshus 的回答,但我使用的是 kotlin,而不是问题中的时间戳,我按分数排序,这应该是相似的。我不确定 firebase 是否具有升序或降序功能,但这就是我当前项目中对我有用的功能。我希望它能在不久的将来帮助到其他人。
FirebaseFirestore.getInstance().collection("leaderboard")
.orderBy("score")
.addSnapshotListener { snapshot, exception ->
if (exception != null) {
Log.e("Exception:", "Could not retrieve scores ${exception.localizedMessage}")
}
if (snapshot != null) {
scores.clear()
for (document in snapshot.documents) {
val data = document.data
val name = data?.get("name") as? String
val score = data?.get("score") as? Number
val documentId = document.id
val newScore = Score(name, score, documentId)
scores.add(newScore)
}
scores.reverse()
scoresAdapter.notifyDataSetChanged()
}
}
这对我有用。
编码愉快!
据我了解没有降序方法,默认只有升序,但您可以手动反转。有关详细信息,请阅读有关实时数据库https://firebase.google.com/docs/database/android/lists-of-data#sorting_and_filtering_data
排序和过滤数据的官方文档
这是一个客户端解决方案,它会在填充列表后根据 firebase 数据库中的特定子项对数据进行排序
Collections.sort(list, new Comparator<ModuleClass>() {
@Override
public int compare(ModuleClass module, ModuleClass t1) {
return Integer.compare(module.getViews(), t1.getViews());
}
});
如果您将数组列表传递给 recyclerView,您可以这样做:
FirebaseDatabase.getInstance().getReference().child("parent_id")
.child("id").orderByChild("count");
tpDBListener = tpDatabaseRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
tpUploads.clear();
for(DataSnapshot postSnapshot : snapshot.getChildren()){
newUpload pupload = postSnapshot.getValue(newUpload.class);
pupload.setKey(postSnapshot.getKey());
tpUploads.add(pupload);//add new object on end
//tpUploads.add(0,pupload);//add new object at beginning
}
tpAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(home.this, error.getMessage(),Toast.LENGTH_SHORT).show();
}
});
翻转顺序,所以第一个是最后一个,最后一个是第一个我建议在将值放入数据库时将其作为 9999999999 然后 -1 用于您想要的任何顺序然后使用:
如果您不是按值或子项对它们进行排序。
tpUploads.add(0, pupload);//add new object at beginning
如果您想按值排序,这是更好的方法,并在数据库中将其初始化为 9999999999,然后将其值初始化为 -1
.orderBy("child_ID")
firebase 将尝试读取每个数字,例如 1 在 6 之前,但由于第一个数字,10 也会在 6 之前。这就是为什么我以 9999999999 作为起始值并相应地减少的原因
public static List<'YourModel> desireList= new ArrayList<>();
//您对“ORDERBY”、“名称”或键等的实时数据库查询
@Override
public void onDataChange(DataSnapshot dataSnapshot)
{
desireList.clear();
List<YourModel>tempList = new ArrayList<>();//Create temp list Object.
for (DataSnapshot dataSnapshotList : dataSnapshot.getChildren())
{
tempList.add(new YourModel(
dataSnapshotList.child("Name").getValue() + "",
dataSnapshotList.getKey() + "",
dataSnapshotList.child("ORDERBY").getValue() + ""));
}
//Save object list in reverse order start.
for (int i =tempList.size(); i>0; i--)
{
desireList.add(tempList.get(i-1));
}
//Save object list in reverse order end.
tempList.clear(); //To clear memory only(not required.)
//Then update your adapter
yoursAdapter.notifyDataSetChanged();
}
我正在将数据存储在 Firebase 存储中。
具有属性 timestamp
的对象 Comment
。当我将数据从设备推送到 Firebase 时,我用 currentTime 填充 timestamp
并存储在 long
数据类型中。
当我使用 firebaseRef.orderByChild("timestamp").limitToLast(15)
检索数据时,结果并未按照我的预期进行排序。
我什至玩过规则但没有结果:
{
"rules": {
".read": true,
".write": true,
".indexOn": "streetrate",
"streetrate": {
".indexOn": ".value"
}
}
}
我尝试在 String
数据类型中存储 timestamp
,同样的问题。
Firebase 可以按给定的 属性 对项目进行升序排序,然后 returns 前 N 个项目 (limitToFirst()
) 或最后 N 个项目 (limitToLast()
).无法表明您希望项目按降序排列。
有两个选项可以获得您想要的行为:
使用 Firebase 查询获取正确的数据,然后在客户端重新排序
向数据添加一个具有降序值的字段
对于后一种方法,通常有一个倒置的时间戳。
-1 * new Date().getTime();
我已经通过扩展 FirebaseListAdapter 和覆盖 getItem 方法解决了问题:
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));
}
}
@Monet_z_Polski 方法,基于
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
对于不自动更新 FirebaseRecyclerView 确实有奇怪的影响(实时更改不会触发 PopulateViewHolder)。所以,最好的选择是使用负键索引数据。
在客户端排序很简单,不需要更多的系统资源。 每个数据快照都有 previousChildkey 字段。如果要 desc 排序,想象 previousChildkey 是 nextChildKey。 这是我的样本:
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);
}
}
}
如果您使用回收器视图来呈现该数据,我发现了一个很好的解决方案...
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
// And set it to RecyclerView
mRecyclerView.setLayoutManager(mLayoutManager);
它将反转数据渲染...
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);
我没有看到任何反转数据的选项。但是一种粗暴的方法是获取数据。
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();
}
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
})
可以使用 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
也可以与 RecyclerView
如果您在 Web 上执行此操作,则可以将值推送到数组中,然后以相反的顺序打印存储的值。
var a=[]; //declaring an array a.
var num=snapshot.numChildren(); //storing number of children in var num.
a.push(snapshot.val()); // pushing data in the array.
if (a.length==num){ //checking if length of array is same as number of children.
a.reverse(); //reversing the array elements.
for(i=0; i<num; i++){
a[i].name;//this will sort the data in descending order.
}
}
添加一列,即时间戳,值为 (-1*System.currentTimeMillis())
并在获取数据时使用 orderByChild("timestamp").limitToFirst(15)
或 orderByChild("timestamp").limitToLast(15)
根据您的要求。
以排序的方式获取数据是一种聪明的方式,因为 firebase 没有降序规则。
很简单,使用-1,-2,-3等在firebase中存储数据database.Now数据会在recyclerView中倒序显示
-3
-2
-1
我发现目前的firebase版本支持降序排序:
citiesRef.orderBy("name", "desc").limit(3)
https://firebase.google.com/docs/firestore/query-data/order-limit-data
希望对您有所帮助
您可以简单地反转您正在使用的列表(ListView 或 RecyclerView)。
基于 Himanshus 的回答,但我使用的是 kotlin,而不是问题中的时间戳,我按分数排序,这应该是相似的。我不确定 firebase 是否具有升序或降序功能,但这就是我当前项目中对我有用的功能。我希望它能在不久的将来帮助到其他人。
FirebaseFirestore.getInstance().collection("leaderboard")
.orderBy("score")
.addSnapshotListener { snapshot, exception ->
if (exception != null) {
Log.e("Exception:", "Could not retrieve scores ${exception.localizedMessage}")
}
if (snapshot != null) {
scores.clear()
for (document in snapshot.documents) {
val data = document.data
val name = data?.get("name") as? String
val score = data?.get("score") as? Number
val documentId = document.id
val newScore = Score(name, score, documentId)
scores.add(newScore)
}
scores.reverse()
scoresAdapter.notifyDataSetChanged()
}
}
这对我有用。 编码愉快!
据我了解没有降序方法,默认只有升序,但您可以手动反转。有关详细信息,请阅读有关实时数据库https://firebase.google.com/docs/database/android/lists-of-data#sorting_and_filtering_data
排序和过滤数据的官方文档这是一个客户端解决方案,它会在填充列表后根据 firebase 数据库中的特定子项对数据进行排序
Collections.sort(list, new Comparator<ModuleClass>() {
@Override
public int compare(ModuleClass module, ModuleClass t1) {
return Integer.compare(module.getViews(), t1.getViews());
}
});
如果您将数组列表传递给 recyclerView,您可以这样做:
FirebaseDatabase.getInstance().getReference().child("parent_id")
.child("id").orderByChild("count");
tpDBListener = tpDatabaseRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
tpUploads.clear();
for(DataSnapshot postSnapshot : snapshot.getChildren()){
newUpload pupload = postSnapshot.getValue(newUpload.class);
pupload.setKey(postSnapshot.getKey());
tpUploads.add(pupload);//add new object on end
//tpUploads.add(0,pupload);//add new object at beginning
}
tpAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(home.this, error.getMessage(),Toast.LENGTH_SHORT).show();
}
});
翻转顺序,所以第一个是最后一个,最后一个是第一个我建议在将值放入数据库时将其作为 9999999999 然后 -1 用于您想要的任何顺序然后使用: 如果您不是按值或子项对它们进行排序。
tpUploads.add(0, pupload);//add new object at beginning
如果您想按值排序,这是更好的方法,并在数据库中将其初始化为 9999999999,然后将其值初始化为 -1
.orderBy("child_ID")
firebase 将尝试读取每个数字,例如 1 在 6 之前,但由于第一个数字,10 也会在 6 之前。这就是为什么我以 9999999999 作为起始值并相应地减少的原因
public static List<'YourModel> desireList= new ArrayList<>();
//您对“ORDERBY”、“名称”或键等的实时数据库查询
@Override
public void onDataChange(DataSnapshot dataSnapshot)
{
desireList.clear();
List<YourModel>tempList = new ArrayList<>();//Create temp list Object.
for (DataSnapshot dataSnapshotList : dataSnapshot.getChildren())
{
tempList.add(new YourModel(
dataSnapshotList.child("Name").getValue() + "",
dataSnapshotList.getKey() + "",
dataSnapshotList.child("ORDERBY").getValue() + ""));
}
//Save object list in reverse order start.
for (int i =tempList.size(); i>0; i--)
{
desireList.add(tempList.get(i-1));
}
//Save object list in reverse order end.
tempList.clear(); //To clear memory only(not required.)
//Then update your adapter
yoursAdapter.notifyDataSetChanged();
}