如何获取用户的当前位置并使用OverlayItem将其绘制在地图上

时间:2014-03-25 08:47:29

标签: java android-fragments location overlayitem

我现在正致力于在地图上绘制公共汽车和公共汽车站的绘图。一个任务是获取用户的当前位置,并在应用程序暂停时停止更新,并在应用程序恢复时继续更新。此外,位置更新最多每10秒发生一次,或者位置变化至少25米。我需要在地图上绘制用户的当前位置。

这是MapDisplayFragment的代码。这里添加了OverlayItems(包括表示用户位置的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();
            }
        }
    }
}

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,但在google上搜索后,我发现mapview已被弃用了。因此,您必须使用地图片段并扩展fragmentActivity而不是mapactivity