【问题标题】:Coupling FirebaseRecyclerViewAdapter to a Boolean/String Map.Entry将 FirebaseRecyclerViewAdapter 耦合到布尔/字符串 Map.Entry
【发布时间】:2016-04-06 04:16:20
【问题描述】:

我在我的应用程序的许多位置使用com.firebaseui:firebase-ui:0.2.0 库中的FirebaseRecyclerViewAdapter。我的问题是如何在查询参数返回多个“索引”条目值(Map.Entry)的情况下应用它。

如 Firebase 文档 (https://www.firebase.com/docs/android/guide/structuring-data.html) 中所述,我使用索引来保持数据结构平坦。这导致我需要将这些索引绑定到我的 ViewHolder 的情况。在填充视图方法中,我使用索引的键来检索数据以填充视图。

我在创建适配器时遇到问题,不确定如何在布尔/字符串 Map.Entry 的情况下定义“modelClass”参数:

mAdapter = new FirebaseRecyclerViewAdapter<Map.Entry<String, Boolean>, ItemViewHolder>(???.class, R.layout.my_card, ItemViewHolder.class, getItemIndexQuery(mKey) ) {
...
}

【问题讨论】:

  • 刚刚发现在这种情况下我需要使用布尔作为模型类类型。这样做会使适配器工作,但也很无用(因为我需要键而不是值)。
  • 你能添加一个你试图加载到你的问题的 JSON 的 sn-p(作为文本,请不要截图)吗?我想试一试...

标签: android firebase firebaseui


【解决方案1】:

您的值是Boolean,而不是Map。所以你的评论是正确的:你需要为值类型指定Boolean/Boolean.class。为了能够查找密钥,您需要升级到 FirebaseUI-Android 0.2.2。在那个版本中,我们添加了一个populateViewHolder(VH, T, int) 重载,它获取项目的位置作为参数。这样,您就可以查找项目的密钥了。

说这是你的 JSON 结构:

{
  "items": {
    "pushid1": "Fri Jan 01 2016 16:40:54 GMT-0800 (PST)",
    "pushid2": "Fri Jan 01 2016 16:41:07 GMT-0800 (PST)",
    "pushid3": "Fri Jan 01 2016 16:41:25 GMT-0800 (PST)",
    "pushid4": "Fri Jan 01 2016 16:41:37 GMT-0800 (PST)",
    "pushid5": "Fri Jan 01 2016 16:42:04 GMT-0800 (PST)"
  },
  "index": {
    "pushid1": true,
    "pushid3": true,
    "pushid5": true
  }
}

所以我们存储代表日期/时间的字符串,并有一个索引来选择这些项目的子集。

我们现在可以从索引中加载节点,然后加载这些节点引用的项目并将它们显示在视图中:

FirebaseRecyclerViewAdapter<Boolean, ItemViewHolder> adapter = 
    new FirebaseRecyclerViewAdapter<Boolean, ItemViewHolder>(
        Boolean.class, android.R.layout.two_line_list_item, ItemViewHolder.class, ref.child("index")){
    protected void populateViewHolder(final ItemViewHolder viewHolder, Boolean model, int position) {
        String key = this.getRef(position).getKey();
        ref.child("items").child(key).addListenerForSingleValueEvent(new ValueEventListener() {
            public void onDataChange(DataSnapshot dataSnapshot) {
                String date = dataSnapshot.getValue(String.class);
                ((TextView)viewHolder.itemView.findViewById(android.R.id.text1)).setText(date);
            }

            public void onCancelled(FirebaseError firebaseError) { }
        });
    }
};

屏幕输出:

完整代码见this repo中的Activity34559171

【讨论】:

  • 弗兰克,addListenerForSingleValueEvent 看起来是异步的。 recyclerview 中的 Viewholder(列表项)被重用。如果一个值获取需要时间,同时由于用户滚动列表项并且它的视图被重用于一些其他数据,那么之前的慢速获取值侦听器可以更新它仍然持有的视图引用。当一个视图被重用时,是否需要取消之前为该视图工作的监听器或同步它?
  • @Puf,如果我想跟踪items 上的变化,而不仅仅是单读。如果不将听众保留在一个集合中,然后在 cleanup() 建议上将它们全部从他们的参考中删除,我想不出更好的方法来做到这一点?
  • 在这个答案中,只有一个字符串“日期”值是从 DataSnapshot 获得的,如果我想获得整个模型而不是一个字符串怎么办?我怎样才能实现它?
【解决方案2】:

我遇到了同样的问题,最后我找到了这个类: FirebaseIndexRecyclerAdapter 这对我来说非常适合。

【讨论】:

    【解决方案3】:

    编辑 4

    我放弃了下面的代码,它是垃圾。 :( 请不要使用它。我重写了database part of Firebase-UI,所以请改用它。

    编辑 1、2 和 3

    由于addListenerForSingleValueEvent 意味着数据将是静态的(除非您更改键的值),这是我在不更改键值的情况下防止静态数据的方法:

    创建事件监听器和持有者对象列表:

    private Map<DatabaseReference, ValueEventListener> mValueEventListeners = new ArrayMap<>();
    private List<TeamInfo> mTeamInfoList = new ArrayList<>();
    

    FirebaseRecyclerAdapter:

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.content_main_recycler_view);
            recyclerView.setHasFixedSize(true);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
    
            mRecyclerViewAdapter = new FirebaseRecyclerAdapter<Long, TeamHolder>(
                    Long.class,
                    R.layout.activity_main_row_layout,
                    TeamHolder.class,
                    Utils.getDatabase()
                            .getReference()
                            .child(Constants.FIREBASE_TEAM_INDEXES)
                            .child(mUser.getUid())
                            .orderByValue()) {
                @Override
                public void populateViewHolder(final TeamHolder teamHolder,
                                               Long teamNumberDoNotUse,
                                               final int position) {
                    DatabaseReference databaseReference = Utils.getDatabase()
                            .getReference()
                            .child(Constants.FIREBASE_TEAMS)
                            .child(getRef(position).getKey());
    
                    if (!mValueEventListeners.containsKey(databaseReference)) {
                        ValueEventListener valueEventListener = new ValueEventListener() {
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                if (dataSnapshot.getValue() != null) {
                                    TeamInfo teamInfo = dataSnapshot.getValue(TeamInfo.class);
    
                                    if (position >= mTeamInfoList.size()) {
                                        String teamNumber = teamInfo.getNumber();
    
                                        teamHolder.setTeamNumber(teamNumber);
                                        teamHolder.setTeamName(teamInfo.getName(),
                                                               MainActivity.this.getString(R.string.no_name));
                                        teamHolder.setTeamLogo(teamInfo.getMedia(), MainActivity.this);
                                        teamHolder.setListItemClickListener(teamNumber,
                                                                            MainActivity.this,
                                                                            dataSnapshot.getKey());
                                        teamHolder.setCreateNewScoutListener(teamNumber,
                                                                             MainActivity.this,
                                                                             dataSnapshot.getKey());
    
                                        mTeamInfoList.add(teamInfo);
                                    } else {
                                        mTeamInfoList.set(position, teamInfo);
                                        notifyItemChanged(position);
                                    }
                                } else {
                                    // This should never happen since we are caching this offline
                                    FirebaseCrash.report(new IllegalStateException(
                                            "MainActivity RecyclerView event listener had null value (ref: " + dataSnapshot.getRef() + "pointed to non existent data)"));
                                }
                            }
    
                            public void onCancelled(DatabaseError databaseError) {
                                FirebaseCrash.report(databaseError.toException());
                            }
                        };
    
                        databaseReference.addValueEventListener(valueEventListener);
                        mValueEventListeners.put(databaseReference, valueEventListener);
                    } else {
                        String teamNumber = mTeamInfoList.get(position).getNumber();
    
                        teamHolder.setTeamNumber(teamNumber);
                        teamHolder.setTeamName(mTeamInfoList.get(position).getName(),
                                               MainActivity.this.getString(R.string.no_name));
                        teamHolder.setTeamLogo(mTeamInfoList.get(position).getMedia(), MainActivity.this);
                        teamHolder.setListItemClickListener(teamNumber, MainActivity.this, getRef(position).getKey());
                        teamHolder.setCreateNewScoutListener(teamNumber, MainActivity.this, getRef(position).getKey());
                    }
                }
            };
    
            recyclerView.setAdapter(mRecyclerViewAdapter);
    

    在你的OnDestroy

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mRecyclerViewAdapter != null) {
            mRecyclerViewAdapter.cleanup();
        }
    
        for (DatabaseReference databaseReference : mValueEventListeners.keySet()) {
                    databaseReference.removeEventListener(mValueEventListeners.get(databaseReference));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-09
      • 2019-07-03
      • 1970-01-01
      • 2015-02-07
      • 1970-01-01
      • 2020-07-03
      • 2013-06-13
      • 2017-07-31
      • 2010-10-04
      相关资源
      最近更新 更多