将 FirebaseRecyclerViewAdapter 耦合到 Boolean/String Map.Entry
Coupling FirebaseRecyclerViewAdapter to a Boolean/String Map.Entry
我在应用程序的许多位置使用 com.firebaseui:firebase-ui:0.2.0
库中的 FirebaseRecyclerViewAdapter
。我的问题是如何在查询参数 returns 多个 'index' 条目值 (Map.Entry) 的情况下应用它。
如 Firebase 文档 (https://www.firebase.com/docs/android/guide/structuring-data.html) 中所述,我使用索引来保持数据结构平坦。这导致我需要将这些索引绑定到我的 ViewHolder 的情况。在填充视图方法中,我使用索引的键来检索数据以填充查看器。
我在创建适配器时遇到问题,不确定如何在 Boolean/String Map.Entry:
的情况下定义 'modelClass' 参数
mAdapter = new FirebaseRecyclerViewAdapter<Map.Entry<String, Boolean>, ItemViewHolder>(???.class, R.layout.my_card, ItemViewHolder.class, getItemIndexQuery(mKey) ) {
...
}
您的值是 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
}
}
所以我们存储表示 date/times 的字符串,并有一个索引 select 这些项目的子集。
我们现在可以从索引加载节点,然后加载这些节点引用的项目并在视图中显示它们:
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
。
编辑 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));
}
}
我遇到了同样的问题,最后我找到了这个 class:
FirebaseIndexRecyclerAdapter
这非常适合我。
我在应用程序的许多位置使用 com.firebaseui:firebase-ui:0.2.0
库中的 FirebaseRecyclerViewAdapter
。我的问题是如何在查询参数 returns 多个 'index' 条目值 (Map.Entry) 的情况下应用它。
如 Firebase 文档 (https://www.firebase.com/docs/android/guide/structuring-data.html) 中所述,我使用索引来保持数据结构平坦。这导致我需要将这些索引绑定到我的 ViewHolder 的情况。在填充视图方法中,我使用索引的键来检索数据以填充查看器。
我在创建适配器时遇到问题,不确定如何在 Boolean/String Map.Entry:
的情况下定义 'modelClass' 参数mAdapter = new FirebaseRecyclerViewAdapter<Map.Entry<String, Boolean>, ItemViewHolder>(???.class, R.layout.my_card, ItemViewHolder.class, getItemIndexQuery(mKey) ) {
...
}
您的值是 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
}
}
所以我们存储表示 date/times 的字符串,并有一个索引 select 这些项目的子集。
我们现在可以从索引加载节点,然后加载这些节点引用的项目并在视图中显示它们:
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
。
编辑 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));
}
}
我遇到了同样的问题,最后我找到了这个 class: FirebaseIndexRecyclerAdapter 这非常适合我。