I am creating a app that will read data from firebase and display it on a map. The app keeps crashing because there are hell lot of records to retrieve from the database. I need a way with which I get only the latest node data and not the entire data snapshot.
MainActivity.java:
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback{
FirebaseDatabase db;
DatabaseReference dbReference;
TextView speed_disp;
public List<LatLng> polygon;
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
private GoogleMap googleMap;
private double latitude=19.10815888216128;
private double longitude=72.83706388922495;
public void setCord(String lat,String lon){
this.latitude=Double.parseDouble(lat);
this.longitude=Double.parseDouble(lon);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
polygon = new PolyList<>(10);
setContentView(R.layout.activity_main);
db = FirebaseDatabase.getInstance();
speed_disp=findViewById(R.id.speed);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 1000);
// }
try{
dbReference = db.getReference("Data");
dbReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot datasnapshot) {
Log.d("Lat",datasnapshot.getValue().toString());
for (DataSnapshot snapshot: datasnapshot.getChildren()) {
String latitude = snapshot.child("lat").getValue(String.class);
String longitude = snapshot.child("lon").getValue(String.class);
String speed = snapshot.child("speed").getValue(String.class);
speed_disp.setText(speed);
setCord(latitude,longitude);
googleMap.clear();
double lat = getLatitude();
double lon = getLongitude();
LatLng current=new LatLng(lat,lon);
// Add marker position to polygon list
polygon.add(current);
// Draw polyline
if (polygon.size() >= 2) {
PolylineOptions polylineOptions = new PolylineOptions()
.addAll(polygon)
.width(5)
.color(Color.RED);
googleMap.addPolyline(polylineOptions);
}
googleMap.addMarker(new MarkerOptions().position(current).title("Current Location"));
// Move camera to marker
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(current,20 ));
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(MainActivity.this,"Read error!!!",Toast.LENGTH_SHORT).show();
}
});
}catch (Error e) {
Toast.makeText(MainActivity.this, "Read module error", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
this.googleMap=googleMap;
googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
// LatLng current=new LatLng(19.10815888216128,72.83706388922495);
// this.googleMap.addMarker(new MarkerOptions().position(current).title("Dub maro pls!!"));
// this.googleMap.moveCamera(CameraUpdateFactory.newLatLng(current));
}
}
Firebase:
I want to read only the newest node from the real-time database. Also, I would appreciate if you guys could improve my code.
2
Answers
It looks like you use
push
to add children toData
, which means you can use this approach to get only the most recently added child node:Also see the Firebase documentation on:
To read only the newest node from the real-time database in Firebase, you can utilize the
limitToLast()
method in your database reference query. This method ensures that only the specified number of child nodes, starting from the last one, are retrieved. In your case, you can set the limit to 1 to get only the latest node.Here’s how you can modify your
dbReference
to achieve this:This modification ensures that only the latest node will be retrieved, thus reducing the amount of data processed and potentially improving the performance of your app.
Regarding your code, there are some improvements that can be made for better efficiency and readability:
Use
childEventListener
instead ofvalueEventListener
: Since you only need to listen for the latest node,ChildEventListener
is more suitable as it listens for changes at the child level.Move Google Map related code out of the loop: You don’t need to clear the map and move the camera for each data snapshot received. Instead, you can move these operations outside the loop to improve efficiency.
Handle potential null values: Ensure that you handle cases where
snapshot.child("lat")
,snapshot.child("lon")
, orsnapshot.child("speed")
return null values.Use appropriate data types: Consider using appropriate data types for latitude, longitude, and speed instead of storing them as strings.
Here’s an improved version of your code:
This version should be more efficient and handle potential null values more gracefully. Make sure to replace the existing
addValueEventListener
withaddChildEventListener
.