所以我已经使用Firebase几个月了。我能够轻松实现所有CRUD操作。我目前正在开发一款具有Uber像汽车追踪动画这样的应用程序。我当前的模块能够使用google maps API获取“原点”和“目的地”,并使用google的json结果显示从原点到目的地的车辆的炫酷动画,它在各个点之间移动。
我的应用程序能够实时跟踪用户的生活并实时发布到Firebase。我遇到了麻烦,试图弄清楚如何才能跟踪正在行驶的汽车,基本上这是一个具有诸如纬度,经度,速度,方位等位置信息(屏幕截图)的用户?
当前,汽车可以通过折线移动,而折线是从Google地图发回的json结果中解码的。
如何跟踪实时纬度/经度点而不是通过折线?我可以从火力地堡获取经纬度
我的地图活动
<div>
<div>
<p class="tracking">Hello</p>
</div>
<div>
<p class="tracking">Projects</p>
</div>
<div>
<p class="tracking">Social</p>
</div>
<div>
<p class="tracking">Contact</p>
</div>
</div>
我的地图XML
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;
}
}
我的Firebase数据库
我的动画(在预定的折线之间移动