'addListenerForSingleValueEvent' 每当 Firebase 引用下的数据发生变化时,都会调用 FirebaseRecyclerAdapter 的 populateViewHolder 方法
'addListenerForSingleValueEvent' in populateViewHolder method of FirebaseRecyclerAdapter gets called whenever data changes under Firebase reference
我在我的应用程序中使用 FirebaseRecyclerAdapter
并尝试通过在它的 populateViewHolder()
方法中获取一些数据然后将值分配给不同的参数来填充它。
这是我的代码:
private void attachRecyclerViewAdapter() {
Query lastFifty = aReference.child(requestID).limitToFirst(50);
mRecyclerViewAdapter = new FirebaseRecyclerAdapter<AModelClass, AModelClass.ViewHolder>(
AModelClass.class, R.layout.a_layout, AModelClass.ViewHolder.class, lastFifty) {
@Override
protected void populateViewHolder(final AModelClass.ViewHolder viewHolder, AModelClass model, int position) {
final String key = this.getRef(position).getKey();
aReference.child(requestID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
aReference.child(requestID).child(key).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
if (dataSnapshot.hasChild("pName") && dataSnapshot.hasChild("pUrl") && dataSnapshot.hasChild("currentLat") && dataSnapshot.hasChild("currentLng")) {
final Map<String, String> map = (Map<String, String>) dataSnapshot.getValue();
pA = map.get("pName");
uidP = map.get("pUrl");
nP.add(map.get("pName"));
cLatPlayers.add(map.get("currentLat").trim());
cLngPlayers.add(map.get("currentLng").trim());
viewHolder.setPNameT(pA);
viewHolder.setPicP(uidP);
viewHolder.setCurrentLatAU(String.valueOf(currentLtAU));
viewHolder.setCurrentLngAU(String.valueOf(currentLnAU));
addMarkers();
layout.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.INVISIBLE);
}
} else {
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
Toast.makeText(getBaseContext(), "no data available yet", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
};
mRecyclerViewAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
super.onItemRangeChanged(positionStart, itemCount);
}
});
aList.setAdapter(mRecyclerViewAdapter);
}
attachRecyclerViewAdapter()
放在 onCreate()
.
这是 aList
在 onCreate()
中的初始化:
aList = (RecyclerView) findViewById(R.id.aList);
aList.setLayoutManager(nLinearLayoutManager);
这是onLocationChanged()
方法:
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
aReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
aReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));
}
每当在从上面检索数据的相同参考下更改位置时,它会将更新的纬度和经度保存到数据库中。
LocationRequest
代码:
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(0);
}
这里一切正常,唯一的问题 是参考代码:aReference.child(requestID).child(key)
或(aReference.child(requestID)
也许?)被调用一次又一次(虽然它应该被调用一次,因为 addListenerForSingleValueEvent
),因此多次填充 nP
、cLatPlayers
、cLngPlayers
以及 addMarkers()
方法被多次调用导致地图出现问题。
为什么会这样,我如何确保它不会被多次调用?
我怀疑如果您遇到循环,那么问题出在您更改值以响应更改的地方。
所以在这里:
viewHolder.setPNameT(pA);
尝试做类似的事情:
if (!viewHolder.getPNameT().equals(pA)) {
viewHolder.setPNameT(pA);
}
因此,仅当值不同时才更新该值,然后它不会注册为已更改并触发对侦听器的另一个调用。这样你每次更改只会得到一个循环。
我没有使用过 FirebaseRecylcerView(直到现在才知道它的存在),但这是我过去用于 TextWatchers 的一般方法。好像是同样的问题。
好吧,我想出了一个非常简单但有效的解决方案。
我只是将更新的位置保存在数据库中的不同引用中,这样每当它发生变化时,aReference.child(requestID)
下的 onDataChange()
就不会被调用,因此代码不会一次又一次地执行。
我把onLocationChanged()
下面的代码改成了:
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
aReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
aReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));
}
对此:
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
anotherReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
anotherReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));
}
但是我仍然无法理解为什么addListenerForSingleValueEvent()
每次都监听数据变化,虽然它应该只监听一次数据变化。
我在我的应用程序中使用 FirebaseRecyclerAdapter
并尝试通过在它的 populateViewHolder()
方法中获取一些数据然后将值分配给不同的参数来填充它。
这是我的代码:
private void attachRecyclerViewAdapter() {
Query lastFifty = aReference.child(requestID).limitToFirst(50);
mRecyclerViewAdapter = new FirebaseRecyclerAdapter<AModelClass, AModelClass.ViewHolder>(
AModelClass.class, R.layout.a_layout, AModelClass.ViewHolder.class, lastFifty) {
@Override
protected void populateViewHolder(final AModelClass.ViewHolder viewHolder, AModelClass model, int position) {
final String key = this.getRef(position).getKey();
aReference.child(requestID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
aReference.child(requestID).child(key).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
if (dataSnapshot.hasChild("pName") && dataSnapshot.hasChild("pUrl") && dataSnapshot.hasChild("currentLat") && dataSnapshot.hasChild("currentLng")) {
final Map<String, String> map = (Map<String, String>) dataSnapshot.getValue();
pA = map.get("pName");
uidP = map.get("pUrl");
nP.add(map.get("pName"));
cLatPlayers.add(map.get("currentLat").trim());
cLngPlayers.add(map.get("currentLng").trim());
viewHolder.setPNameT(pA);
viewHolder.setPicP(uidP);
viewHolder.setCurrentLatAU(String.valueOf(currentLtAU));
viewHolder.setCurrentLngAU(String.valueOf(currentLnAU));
addMarkers();
layout.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.INVISIBLE);
}
} else {
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
Toast.makeText(getBaseContext(), "no data available yet", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
};
mRecyclerViewAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
super.onItemRangeChanged(positionStart, itemCount);
}
});
aList.setAdapter(mRecyclerViewAdapter);
}
attachRecyclerViewAdapter()
放在 onCreate()
.
这是 aList
在 onCreate()
中的初始化:
aList = (RecyclerView) findViewById(R.id.aList);
aList.setLayoutManager(nLinearLayoutManager);
这是onLocationChanged()
方法:
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
aReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
aReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));
}
每当在从上面检索数据的相同参考下更改位置时,它会将更新的纬度和经度保存到数据库中。
LocationRequest
代码:
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(0);
}
这里一切正常,唯一的问题 是参考代码:aReference.child(requestID).child(key)
或(aReference.child(requestID)
也许?)被调用一次又一次(虽然它应该被调用一次,因为 addListenerForSingleValueEvent
),因此多次填充 nP
、cLatPlayers
、cLngPlayers
以及 addMarkers()
方法被多次调用导致地图出现问题。
为什么会这样,我如何确保它不会被多次调用?
我怀疑如果您遇到循环,那么问题出在您更改值以响应更改的地方。
所以在这里:
viewHolder.setPNameT(pA);
尝试做类似的事情:
if (!viewHolder.getPNameT().equals(pA)) {
viewHolder.setPNameT(pA);
}
因此,仅当值不同时才更新该值,然后它不会注册为已更改并触发对侦听器的另一个调用。这样你每次更改只会得到一个循环。
我没有使用过 FirebaseRecylcerView(直到现在才知道它的存在),但这是我过去用于 TextWatchers 的一般方法。好像是同样的问题。
好吧,我想出了一个非常简单但有效的解决方案。
我只是将更新的位置保存在数据库中的不同引用中,这样每当它发生变化时,aReference.child(requestID)
下的 onDataChange()
就不会被调用,因此代码不会一次又一次地执行。
我把onLocationChanged()
下面的代码改成了:
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
aReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
aReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));
}
对此:
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
anotherReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
anotherReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));
}
但是我仍然无法理解为什么addListenerForSingleValueEvent()
每次都监听数据变化,虽然它应该只监听一次数据变化。