问题
I'm using FirebaseRecyclerAdapter
in my app and trying to populate it by fetching some data inside it's populateViewHolder()
method and then assigning values to different parameters.
Here's my code:
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()
is placed in onCreate()
.
Here's aList
initialisation in onCreate()
:
aList = (RecyclerView) findViewById(R.id.aList);
aList.setLayoutManager(nLinearLayoutManager);
Here's onLocationChanged()
method:
@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));
}
which saves updated lat and lng to database whenever location is changed under the same reference from where data is getting retrieved above.
The LocationRequest
code:
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(0);
}
Everything is working just fine here, the only problem is that the code under reference: aReference.child(requestID).child(key)
or (aReference.child(requestID)
maybe?) is getting called again and again (though it is supposed to be called just once because of addListenerForSingleValueEvent
), thus filling nP
, cLatPlayers
, cLngPlayers
multiple times and also the addMarkers()
method is getting called multiple times causing problem in the Map.
Why is this happening and How can I make sure that this doesn't gets called multiple times?
回答1:
I suspect if you're getting a loop then the problem is at the place where you change the values in response to the change.
So here:
viewHolder.setPNameT(pA);
Try doing something like:
if (!viewHolder.getPNameT().equals(pA)) {
viewHolder.setPNameT(pA);
}
So only update the value if it's different and then it won't register as being changed and fire off another call to the listener. This way you only get one loop for each change.
I haven't used FirebaseRecylcerView (didn't know it existed until now) but this is the general approach I've used in the past for TextWatchers. It seems like the same problem.
回答2:
Well I came up with a very simple yet effective solution.
I just saved the updated locations at a different reference in database so that whenever it changes the onDataChange()
under aReference.child(requestID)
is not called and thus the code does not gets executed again and again.
I changed the code under onLocationChanged()
from this:
@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));
}
to this:
@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));
}
But I'm still unable to understand why addListenerForSingleValueEvent()
listens for data changes every time though it is supposed to listen data changes just once.
来源:https://stackoverflow.com/questions/42476569/addlistenerforsinglevalueevent-in-populateviewholder-method-of-firebaserecycle