如何按自定义 属性(不是数据库值)订购 Firebase ListView (FirebaseUI)

How to order Firebase ListView (FirebaseUI) by custom property (not database value)

是否可以让 FirebaseUI ListView 按本地数据模型的 属性(在本例中为 Person.class)排序,而不是按数据库中包含的值排序...实时不少于?

问题:我正在将一个基于位置的应用程序(类似于拼车应用程序)从 PHP/mysql 转换为 firebase。 (顺便说一下,我对 Firebase 感到非常兴奋……而且我已经看到了很多优势)。

出于我们的目的,该应用程序仅显示一个列表视图,其中列出了按距离排序的附近和可用服务提供商。这以前是通过向服务器发送一个 PHP 请求来完成的,其中包括客户的纬度和经度作为 POST 参数。然后服务器将发回 JSON 服务提供商列表。服务器将根据服务提供商与客户的当前距离对结果进行排序。另外... 不可用的服务提供商根本不返回。所有这一切的问题是用户仍然需要 "pull to refresh."

Firebase 方法目前有效,但我只能通过服务提供商的可用性(参见代码)过滤我的(FirebaseUI 支持的)列表视图,但我还没有想到如何订购按距离列出。

下面的代码显示了我正在尝试做的事情。 Person class 代表服务提供者。

所以...假设 Person class 有变量 Person.distance 和 getDistance() 方法 returns 他们的位置(来自 Firebase 数据库)和当前存储在应用用户 phone 中的位置。这个变量显然不能存储在数据库中并用作可比较的值,因为它是相对的并且取决于用户和服务提供商的位置。

有没有一种方法可以使用回收站视图来实现这一点?我会假设它会在适配器内部完成……但这一切都已经包含在 FirebaseUI 中了……而且我的编码还不够好,无法重写 Android 库 classes。感谢您的帮助。

相关代码(工作正常...这不是问题...请先阅读 post):

ref = FirebaseDatabase.getInstance().getReference().child("person");

    Query orderedByAvail_Query = ref.orderByChild("available").equalTo(true);

    FirebaseListAdapter<Person> fireAdapter = new FirebaseListAdapter<Person>(getActivity(),
            Person.class, R.layout.single_row, orderedByAvail_Query) {
        @Override
        protected void populateView(View v, Person person, int position) {

            TextView name_title = (TextView) v.findViewById(R.id.Nickname);
            name_title.setText(person.getNickname());

            if (person.getAvail()){
                name_title.setBackgroundColor(Color.GREEN);
            } else {
                name_title.setBackgroundColor(Color.WHITE);
            }




        }
    };

        // Arraylist<Person> tempList4Sorting = new ArrayList<Person>;

        // for (i=1 to fireAdapter.size){
        // tempList4Sorting.add(fireAdapter.getItem(i);
        // i++;
        // }

        // Collections.sort(tempList4Sorting, Person.distance, DESCENDING);

        // fireAdapter.clearItems();
        // 
        // put sorted items back into the adapter using another for loop

        // fireAdapter.notifyDataSetChanged (?)


    setListAdapter(fireAdapter);

我实现了一个看起来可行的解决方案...虽然我 绝对 选择了简单而不是效率。我不认为我真的 "re-wrote" 什么 -- 更像是在玩旧游戏,"Operation." 不管怎样...我是这样做的:

1) 让 Person class 实现 Comparable,这样 Collection.sort() 就可以工作了。在 compareTo() 方法中,排序是通过 Person.getDistance() 完成的,它简单地计算 lat/lon 与应用程序 运行 的 phone 的 GPS 之间的距离on,以及此人的 lat/lon(从 Firebase 数据库中检索)。

2) 修改FirebaseListActivity中的getItem()方法如下:

@Override
public T getItem(int position) {
    Log.i("XXX", "getItem() was called");


    // put all (parsed) list items into an array

    ArrayList<Person> temp_person_list = new ArrayList();

    for (int i = 1; i<=(mSnapshots.getCount()); i++){

        temp_person_list.add((Person) parseSnapshot(mSnapshots.getItem(i-1)));

    }

    // sort the array based on distance property
    Collections.sort(temp_person_list);


    // return the originally desired position
    return (T) temp_person_list.get(position);

}

我知道这在原则上很糟糕...(我确信更好的方法是在 FirebaseArray class 中添加另一个底层 ArrayList,它会根据距离静默地重新映射索引。 .但坦率地说,这让我头疼)。

无论如何...我也考虑过另一种可能的解决方案(如 Geofire)——使用 geohash 而不是 lat/lon。这样就只有一个(可排序的)位置字段而不是两个......并且可以使用现有的 Firebase 查询方法查询它以实现排序(按邻近度)列表。仍在努力。