我现在正在开发一个与在地图上绘制公共汽车和公共汽车站相关的应用程序。一项任务是获取用户的当前位置并在应用程序暂停时停止更新,并在应用程序恢复时继续更新。此外,位置更新最多每 10 秒发生一次,或者位置变化至少 25 米。我需要在地图上绘制用户的当前位置。
这是 MapDisplayFragment 的代码。此处添加了 OverlayItem(包括表示用户位置的 OverlayItem),看来我需要创建新的类来实现这些功能,而不是像我那样在此类中编写代码。我正在考虑构建两个类:扩展 LocationListener 的 MyLocationListener 和扩展 Fragment 的 MyLocationFragment,但现在我不知道如何开始:更具体地说,我不知道我应该在这些类之间建立什么关系。任何想法?
import java.util.ArrayList;
import java.util.List;
import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.api.IMapController;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.ItemizedIconOverlay;
import org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener;
import org.osmdroid.views.overlay.OverlayItem;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Resources;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import ca.ubc.cpsc210.exception.TranslinkException;
import ca.ubc.cpsc210.nextbus.model.Bus;
import ca.ubc.cpsc210.nextbus.model.BusStop;
import ca.ubc.cpsc210.nextbus.translink.ITranslinkService;
import ca.ubc.cpsc210.nextbus.translink.TranslinkService;
import ca.ubc.cpsc210.nextbus.util.LatLon;
import ca.ubc.cpsc210.nextbus.util.TextOverlay;
/**
* Fragment holding the map in the UI.
*/
public class MapDisplayFragment extends Fragment {
/**
* Log tag for LogCat messages
*/
private final static String LOG_TAG = "MapDisplayFragment";
/**
* Location of Nelson & Granville, downtown Vancouver
*/
private final static GeoPoint NELSON_GRANVILLE
= new GeoPoint(49.279285, -123.123007);
/**
* Overlay for bus markers.
*/
private ItemizedIconOverlay<OverlayItem> busLocnOverlay;
/**
* Overlay for bus stop location
*/
private ItemizedIconOverlay<OverlayItem> busStopLocationOverlay;
/**
* Overlay for legend
*/
private TextOverlay legendOverlay;
/**
* View that shows the map
*/
private MapView mapView;
/**
* Selected bus stop
*/
private BusStop selectedStop;
/**
* Wraps Translink web service
*/
private ITranslinkService tlService;
/**
* Map controller for zooming in/out, centering
*/
private IMapController mapController;
/**
* True if and only if map should zoom to fit displayed route.
*/
private boolean zoomToFit;
/**
* Bus selected by user
*/
private OverlayItem selectedBus;
/**
* User's location icon.
*/
private OverlayItem userLocnIcon;
/**
* Overlay for user current location.
*/
private ItemizedIconOverlay<OverlayItem> userLocnOverlay;
/**
* User's location.
*/
private GeoPoint location;
/**
* Set up Translink service
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(LOG_TAG, "onActivityCreated");
setHasOptionsMenu(true);
tlService = new TranslinkService(getActivity());
Log.d(LOG_TAG, "Stop number for mapping: " + (selectedStop == null ? "not set" : selectedStop.getStopNum()));
}
/**
* Set up map view with overlays for buses and selected bus stop.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(LOG_TAG, "onCreateView");
if (mapView == null) {
mapView = new MapView(getActivity(), null);
mapView.setTileSource(TileSourceFactory.MAPNIK);
mapView.setClickable(true);
mapView.setBuiltInZoomControls(true);
// set default view for map (this seems to be important even when
// it gets overwritten by plotBuses)
mapController = mapView.getController();
mapController.setZoom(mapView.getMaxZoomLevel() - 4);
mapController.setCenter(NELSON_GRANVILLE);
busLocnOverlay = createBusLocnOverlay();
busStopLocationOverlay = createBusStopLocnOverlay();
legendOverlay = createTextOverlay();
userLocnOverlay = createUserLocnOverlay();
// Order matters: overlays added later are displayed on top of
// overlays added earlier.
mapView.getOverlays().add(busStopLocationOverlay);
mapView.getOverlays().add(busLocnOverlay);
mapView.getOverlays().add(userLocnOverlay);
mapView.getOverlays().add(legendOverlay);
}
return mapView;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_map_refresh, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.map_refresh) {
update(false);
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* When view is destroyed, remove map view from its parent so that it can be
* added again when view is re-created.
*/
@Override
public void onDestroyView() {
Log.d(LOG_TAG, "onDestroyView");
((ViewGroup) mapView.getParent()).removeView(mapView);
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(LOG_TAG, "onDestroy");
super.onDestroy();
}
/**
* Update bus locations.
*/
@Override
public void onResume() {
Log.d(LOG_TAG, "onResume");
update(true);
super.onResume();
}
/**
* Set selected bus stop
* @param selectedStop the selected stop
*/
public void setBusStop(BusStop selectedStop) {
this.selectedStop = selectedStop;
}
/**
* Update bus location info for selected stop,
* zoomToFit status and repaint.
*
* @Param zoomToFit true if map must be zoomed to fit (when new bus stop has been selected)
*/
void update(boolean zoomToFit) {
Log.d(LOG_TAG, "update - zoomToFit: " + zoomToFit);
this.zoomToFit = zoomToFit;
if(selectedStop != null) {
new GetBusInfo().execute(selectedStop);
selectedBus = null;
}
mapView.invalidate();
}
/**
* Create the overlay for bus markers.
*/
private ItemizedIconOverlay<OverlayItem> createBusLocnOverlay() {
ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());
OnItemGestureListener<OverlayItem> gestureListener = new OnItemGestureListener<OverlayItem>() {
/**
* Display bus information in dialog box when user taps
* bus.
*
* @param index index of item tapped
* @param oi the OverlayItem that was tapped
* @return true to indicate that tap event has been handled
*/
@Override
public boolean onItemSingleTapUp(int index, OverlayItem oi) {
AlertDialog dlg = createSimpleDialog(oi.getTitle(), oi.getSnippet());
dlg.show();
if(selectedBus != null){
selectedBus.setMarker(getResources().getDrawable(R.drawable.bus));
}
selectedBus = oi;
selectedBus.setMarker(getResources().getDrawable(R.drawable.selected_bus));
mapView.postInvalidate();
return true;
}
@Override
public boolean onItemLongPress(int index, OverlayItem oi) {
// do nothing
return false;
}
};
return new ItemizedIconOverlay<OverlayItem>(
new ArrayList<OverlayItem>(),
getResources().getDrawable(R.drawable.bus),
gestureListener, rp);
}
/**
* Create the overlay for bus stop marker.
*/
private ItemizedIconOverlay<OverlayItem> createBusStopLocnOverlay() {
ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());
OnItemGestureListener<OverlayItem> gestureListener = new OnItemGestureListener<OverlayItem>() {
/**
* Display bus stop description in dialog box when user taps
* stop.
*
* @param index index of item tapped
* @param oi the OverlayItem that was tapped
* @return true to indicate that tap event has been handled
*/
@Override
public boolean onItemSingleTapUp(int index, OverlayItem oi) {
AlertDialog dlg = createSimpleDialog(oi.getTitle(), oi.getSnippet());
dlg.show();
return true;
}
@Override
public boolean onItemLongPress(int index, OverlayItem oi) {
// do nothing
return false;
}
};
return new ItemizedIconOverlay<OverlayItem>(
new ArrayList<OverlayItem>(),
getResources().getDrawable(R.drawable.stop),
gestureListener, rp);
}
private TextOverlay createTextOverlay() {
ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());
Resources res = getResources();
String legend = res.getString(R.string.legend);
return new TextOverlay(rp, legend);
}
/**
* Create the overlay for user location markers.
*/
private ItemizedIconOverlay<OverlayItem> createUserLocnOverlay() {
ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());
OnItemGestureListener<OverlayItem> gestureListener = new OnItemGestureListener<OverlayItem>() {
/**
* Display user location.
*
* @param index index of item tapped
* @param oi the OverlayItem that was tapped
* @return true to indicate that tap event has been handled
*/
@Override
public boolean onItemSingleTapUp(int index, OverlayItem oi) {
// Don't do anything.
return false;
}
@Override
public boolean onItemLongPress(int index, OverlayItem oi) {
// do nothing
return false;
}
};
return new ItemizedIconOverlay<OverlayItem>(
new ArrayList<OverlayItem>(),
getResources().getDrawable(R.drawable.map_pin_blue),
gestureListener, rp);
}
/**
* Plot bus stop
*/
private void plotBusStop() {
LatLon latlon = selectedStop.getLatLon();
GeoPoint point = new GeoPoint(latlon.getLatitude(),
latlon.getLongitude());
OverlayItem overlayItem = new OverlayItem(Integer.valueOf(selectedStop.getStopNum()).toString(),
selectedStop.getLocationDesc(), point);
busStopLocationOverlay.removeAllItems(); // make sure not adding
// bus stop more than once
busStopLocationOverlay.addItem(overlayItem);
}
/**
* Plot buses onto bus location overlay
*
* @param zoomToFit determines if map should be zoomed to bounds of plotted buses
*/
private void plotBuses(boolean zoomToFit) {
List<Bus> buses = selectedStop.getBuses();
Double maxlatSpan = 0.0;
Double maxlonSpan = 0.0;
busLocnOverlay.removeAllItems();
for(Bus b : buses){
Double latDifference = Math.abs(b.getLatLon().getLatitude()-NELSON_GRANVILLE.getLatitude() );
if(latDifference > maxlatSpan && (latDifference < 2.0)){
maxlatSpan = latDifference;
}
Double lonDifference = Math.abs(b.getLatLon().getLongitude()-NELSON_GRANVILLE .getLongitude());
if(lonDifference > maxlonSpan && (lonDifference < 2.0)){
maxlonSpan = lonDifference;
}
String routeNo = b.getRoute().getName();
String desc = b.getDescription();
LatLon latlon = b.getLatLon();
GeoPoint point = new GeoPoint(latlon.getLatitude(), latlon.getLongitude());
OverlayItem overlayItem = new OverlayItem(routeNo, desc, point);
busLocnOverlay.addItem(overlayItem);
}
if(zoomToFit){
mapController.zoomToSpan((int)Math.abs(maxlatSpan*2E6), (int) Math.abs(maxlonSpan*2E6));
}
}
/**
* Helper to create simple alert dialog to display message
* @param title the title to be displayed at top of dialog
* @param msg message to display in dialog
* @return the alert dialog
*/
private AlertDialog createSimpleDialog(String title, String msg) {
AlertDialog.Builder dialogBldr = new AlertDialog.Builder(getActivity());
dialogBldr.setTitle(title);
dialogBldr.setMessage(msg);
dialogBldr.setNeutralButton(R.string.ok, null);
return dialogBldr.create();
}
public void getUserLocation() {
Criteria criteria = new Criteria();
Context cont = new Activity();
LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
String bestProvider = locationManager.getBestProvider(criteria, true);
Location userLocation = locationManager.getLastKnownLocation(bestProvider);
location = new GeoPoint(userLocation.getLatitude() * 1E6, userLocation.getLongitude() * 1E6);
}
private void plotUserLocation() {
getUserLocation();
userLocnIcon = new OverlayItem("UserLocn", "User location", location);
userLocnOverlay.addItem(userLocnIcon);
}
/**
* Asynchronous task to get bus location estimates from Translink service.
* Displays progress dialog while running in background.
*/
private class GetBusInfo extends
AsyncTask<BusStop, Void, Void> {
private ProgressDialog dialog = new ProgressDialog(getActivity());
private boolean success = true;
@Override
protected void onPreExecute() {
dialog.setMessage("Retrieving bus info...");
dialog.show();
}
@Override
protected Void doInBackground(BusStop... selectedStops) {
BusStop selectedStop = selectedStops[0];
try {
tlService.addBusLocationsForStop(selectedStop);
} catch (TranslinkException e) {
e.printStackTrace();
success = false;
}
return null;
}
@Override
protected void onPostExecute(Void dummy) {
dialog.dismiss();
if (success) {
plotBuses(zoomToFit);
plotBusStop();
plotUserLocation();
mapView.invalidate();
} else {
AlertDialog dialog = createSimpleDialog("Error", "Unable to retrieve bus location info...");
dialog.show();
}
}
}
}
任何帮助表示赞赏。