так что я использую FireBase в течение нескольких месяцев. Я могу легко реализовать все операции CRUD. В настоящее время я работаю над приложением, которое имеет Uber, как анимация отслеживания автомобиля. Мой текущий модуль может принимать «Исходный пункт» и «Пункт назначения» с помощью API карт Google и отображать классную анимацию транспортного средства, движущегося из исходного пункта в пункт назначения с помощью результата json от Google, который перемещается через точки.
Мое приложение может отслеживать пользователей в реальном времени и публиковать их в режиме реального времени. Я попал в ловушку, пытаясь выяснить, как я могу отследить движущийся автомобиль, который в основном является пользователем с данными о местоположении, такими как широта, долгота, скорость, направление и т. Д. (Скриншот)?
В настоящее время автомобиль может перемещаться по полилиниям, декодированным из результата json, который отправляет карта Google.
Как отслеживать точки широты / долготы в реальном времени вместо прохождения линий поли? Я могу получить лат / лонг из firebase
Активность моих карт
package malcolmmaima.dishi.View.Map;
import android.animation.ValueAnimator;
import android.graphics.Color;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.maps.model.SquareCap;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import malcolmmaima.dishi.R;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import static com.google.android.gms.maps.model.JointType.ROUND;
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String TAG = MapsActivity.class.getSimpleName();
SupportMapFragment mapFragment;
private GoogleMap mMap;
private List<LatLng> polyLineList;
private Marker marker;
private float v;
private double lat, lng;
private Handler handler;
private LatLng startPosition, endPosition;
private int index, next;
private LatLng myLocation;
private Button button;
private EditText destinationEditText;
private String destination;
private PolylineOptions polylineOptions, blackPolylineOptions;
private Polyline blackPolyline, greyPolyLine;
private double myLat, myLng, speed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
Toolbar topToolBar = findViewById(R.id.toolbar);
setSupportActionBar(topToolBar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
//setTitle("Track Nduthi");
setTitle("");
topToolBar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish(); // Go back to previous activity
}
});
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String myPhone = user.getPhoneNumber(); //Current logged in user phone number
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference dbRef = db.getReference(myPhone);
dbRef.child("location").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
if(dataSnapshot1.getKey().equals("latitude")){
myLat = dataSnapshot1.getValue(Double.class) ;
}
if(dataSnapshot1.getKey().equals("longitude")){
myLng = dataSnapshot1.getValue(Double.class);
}
if(dataSnapshot1.getKey().equals("speed")){
speed = dataSnapshot1.getValue(Double.class);
}
//Toast.makeText(MapsActivity.this, "mylat: " + myLat + " mylon: " + myLng + " speed: " + speed, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
polyLineList = new ArrayList<>();
button = findViewById(R.id.btnSearch);
destinationEditText = findViewById(R.id.edtPlace);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
destination = destinationEditText.getText().toString();
destination = destination.replace(" ", "+");
Log.d(TAG, destination);
mapFragment.getMapAsync(MapsActivity.this);
}
});
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
//Default Nairobi
final double latitude = -1.281647;
double longitude = 36.822638;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mMap.setTrafficEnabled(false);
mMap.setIndoorEnabled(false);
mMap.setBuildingsEnabled(false);
mMap.getUiSettings().setZoomControlsEnabled(true);
myLocation = new LatLng(-myLat, myLng);
mMap.addMarker(new MarkerOptions().position(myLocation).title("My Location"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(myLocation));
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
.target(googleMap.getCameraPosition().target)
.zoom(17)
.bearing(30)
.tilt(45)
.build()));
String requestUrl = null;
try {
requestUrl = "https://maps.googleapis.com/maps/api/directions/json?" +
"mode=walking&"
+ "transit_routing_preference=less_walking&"
+ "origin=" + destination + "&"
+ "destination=" + myLat + "," + myLng + "&"
+ "key=" + getResources().getString(R.string.google_directions_key);
Log.d(TAG, requestUrl);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET,
requestUrl, null,
new com.android.volley.Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d(TAG, response + "");
try {
JSONArray jsonArray = response.getJSONArray("routes");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject route = jsonArray.getJSONObject(i);
JSONObject poly = route.getJSONObject("overview_polyline");
String polyline = poly.getString("points");
polyLineList = decodePoly(polyline);
Log.d(TAG, polyLineList + "");
}
//Adjusting bounds
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (LatLng latLng : polyLineList) {
builder.include(latLng);
}
LatLngBounds bounds = builder.build();
CameraUpdate mCameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 2);
mMap.animateCamera(mCameraUpdate);
polylineOptions = new PolylineOptions();
polylineOptions.color(Color.GRAY);
polylineOptions.width(5);
polylineOptions.startCap(new SquareCap());
polylineOptions.endCap(new SquareCap());
polylineOptions.jointType(ROUND);
polylineOptions.addAll(polyLineList);
greyPolyLine = mMap.addPolyline(polylineOptions);
blackPolylineOptions = new PolylineOptions();
blackPolylineOptions.width(5);
blackPolylineOptions.color(Color.BLACK);
blackPolylineOptions.startCap(new SquareCap());
blackPolylineOptions.endCap(new SquareCap());
blackPolylineOptions.jointType(ROUND);
blackPolyline = mMap.addPolyline(blackPolylineOptions);
mMap.addMarker(new MarkerOptions()
.position(polyLineList.get(polyLineList.size() - 1)));
ValueAnimator polylineAnimator = ValueAnimator.ofInt(0, 100);
polylineAnimator.setDuration(2000);
polylineAnimator.setInterpolator(new LinearInterpolator());
polylineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
List<LatLng> points = greyPolyLine.getPoints();
int percentValue = (int) valueAnimator.getAnimatedValue();
int size = points.size();
int newPoints = (int) (size * (percentValue / 100.0f));
List<LatLng> p = points.subList(0, newPoints);
blackPolyline.setPoints(p);
}
});
polylineAnimator.start();
marker = mMap.addMarker(new MarkerOptions().position(myLocation)
.flat(true)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.nduthi_guy)));
handler = new Handler();
index = -1;
next = 1;
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (index < polyLineList.size() - 1) {
index++;
next = index + 1;
}
if (index < polyLineList.size() - 1) {
startPosition = polyLineList.get(index);
endPosition = polyLineList.get(next);
}
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(3000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
v = valueAnimator.getAnimatedFraction();
lng = v * endPosition.longitude + (1 - v)
* startPosition.longitude;
lat = v * endPosition.latitude + (1 - v)
* startPosition.latitude;
LatLng newPos = new LatLng(lat, lng);
marker.setPosition(newPos);
marker.setAnchor(0.5f, 0.5f);
marker.setRotation(getBearing(startPosition, newPos));
mMap.moveCamera(CameraUpdateFactory
.newCameraPosition
(new CameraPosition.Builder()
.target(newPos)
.zoom(15.5f)
.build()));
}
});
valueAnimator.start();
handler.postDelayed(this, 3000);
}
}, 3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new com.android.volley.Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error + "");
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(jsonObjectRequest);
} catch (Exception e) {
e.printStackTrace();
}
}
private List<LatLng> decodePoly(String encoded) {
List<LatLng> poly = new ArrayList<>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
LatLng p = new LatLng((((double) lat / 1E5)),
(((double) lng / 1E5)));
poly.add(p);
}
return poly;
}
private float getBearing(LatLng begin, LatLng end) {
double lat = Math.abs(begin.latitude - end.latitude);
double lng = Math.abs(begin.longitude - end.longitude);
if (begin.latitude < end.latitude && begin.longitude < end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)));
else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
return -1;
}
}
Мои карты XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".View.Map.MapsActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:maxHeight="@dimen/actionBarSize"
android:background="@color/colorPrimary"
android:layout_width="match_parent"
android:layout_height="@dimen/actionBarSize">
</android.support.v7.widget.Toolbar>
<LinearLayout
android:id="@+id/layout_panel"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp">
<EditText
android:id="@+id/edtPlace"
android:hint="Enter Place"
android:layout_margin="10dp"
android:layout_weight="5"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btnSearch"
android:text="Go"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<fragment
android:layout_below="@+id/layout_panel"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".View.Map.MapsActivity"/>
</RelativeLayout>
Моя база данных Firebase
![Firebase D](https://i.stack.imgur.com/ONkes.png)
Моя анимация (Перемещение по заранее заданным линиям поли
![enter image description here](https://i.stack.imgur.com/Ql8MX.jpg)