阻止Google SupportMapFragment重新加载

时间:2014-03-06 12:19:44

标签: android google-maps supportmapfragment

我在使用SupportMapFragment开发Android应用时遇到了一些麻烦。目前,当我切换片段时,我只是隐藏了SupportMapFragment并将CameraPosition保存在SharedPreferences中。然后,当我再次显示地图时,它会从SharedPreferences加载CameraPosition。这工作正常,但地图本身需要再次加载。必须有一种方法来保存地图的方式,它几乎不需要任何时间弹出备份,如只是将它移动到背景或什么?谁能帮我这个?谢谢!

2 个答案:

答案 0 :(得分:1)

一些截图证明我已经完成了它:

Multipane mode of my app

我的应用的多重模式

Moved to singlepane and selected the map('Kort' in danish) tab

移至单张窗格并选择地图(丹麦语中的'Kort')标签。

发生的事情是:

  1. 字段变量保存映射片段设置为单窗格地图片段,如果第一次看到地图时新创建,或使用findFragmentByTag恢复。 在这种情况下,它使用多窗格模式中的片段进行恢复。
  2. 由于使用现有片段恢复地图,地图的GoogleMap实例将与我们存储在GoogleMapModule中的实例相同(见下文),因此保留了状态。
  3. 这使得地图立即显示,具有标记等,因为它们处于多窗格模式。


    将对地图片段的引用存储为字段变量,并尽可能使用它。这样您只需要担心一个映射实例(使用findFragmentByTag重新实例化它)。

    其次,为了存储地图的状态,我存储了GoogleMap,你可以在地图片段上调用getMap(),在Activity中独立于Activity(与应用程序生命周期绑定的单例)。也就是说,我的地图片段将尽可能获取存储的GoogleMap对象并将其用于所有操作(缩放,标记等)。

    以下是我使用的GoogleMapModule(如果您可以使用其中的一部分):

    @Singleton
    public class GoogleMapsModule extends StandardModule {
    
        private final GoogleMapsModulePreferences modulePreferences;
    
        public class GoogleMapsModulePreferences implements ModulePreferences {
    
            @Override public boolean isActivated() {
                return isActivated();
            }
    
            public int getAddressEntry() {
                return preferences
                        .getStringInt(R.string.key_googlemaps_address_entry);
            }
    
            public int getCityEntry() {
                return preferences.getStringInt(R.string.key_googlemaps_city_entry);
            }
    
        }
    
        public GoogleMapsModulePreferences getPreferences() {
            return modulePreferences;
        }
    
        public interface GoogleMapsCallback {
            public void mapReady(GoogleMap map);
        }
    
        public interface FetchAddressCallback {
            public void addressFound(AddressHolder addressHolder);
    
            public void addressLookupFailed();
        }
    
        private static final String TAG = "GoogleMapsModule";
    
        public static final int MAPTYPE_NORMAL = 0;
        public static final int MAPTYPE_SATELITE = 1;
        public static final int MAPTYPE_TERRAIN = 2;
        public static final int MAPTYPE_HYBRID = 3;
    
        private AddressHolder addressPin;
    
        private GoogleMap mGoogleMap;
        private Geocoder geocoder;
    
        private GoogleMapsCallback googleMapsCallback;
    
        private final Preferences preferences;
    
        @Inject public GoogleMapsModule(@ForApplication Context context,
                Preferences preferences, ExpirationCoreModule expiration,
                ParseCoreModule parse) {
            super(context, preferences, expiration, parse, MODULES.GOOGLEMAPS);
    
            this.modulePreferences = new GoogleMapsModulePreferences();
            this.preferences = preferences;
    
            Log.i(TAG, "CREATING MODULE " + TAG);
    
            geocoder = new Geocoder(context, new Locale("da_DK"));
        }
    
        @Override public void load() {
    
            MapsInitializer.initialize(context);
            loadEnded();
    
        }
    
        public void setGoogleMapsCallback(GoogleMapsCallback mapReadyCallback) {
            this.googleMapsCallback = mapReadyCallback;
        }
    
        public void destroyMap() {
            mGoogleMap = null;
        };
    
        public void clearMap() {
            clearMap(false);
        }
    
        public void clearMap(boolean keepAddressPin) {
            this.googleMapsCallback = null;
    
            if (mGoogleMap != null) {
                mGoogleMap.clear();
    
                if (keepAddressPin && addressPin != null) {
                    addAddressPin(addressPin);
                }
            }
        }
    
        public void setMap(GoogleMap map) {
            if (mGoogleMap == null) {
                mGoogleMap = map;
                mGoogleMap.setMyLocationEnabled(true);
                mGoogleMap.setTrafficEnabled(true);
                mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            }
    
            if (googleMapsCallback != null) {
                googleMapsCallback.mapReady(mGoogleMap);
            }
        }
    
        public GoogleMap getMap() {
            return mGoogleMap;
        }
    
        public void setMapType(int maptype) {
            if (mGoogleMap != null) {
                mGoogleMap.setMapType(maptype);
            }
        }
    
        public String mapType(int maptype) {
            switch (maptype) {
            case MAPTYPE_NORMAL:
    
                return "Normal";
            case MAPTYPE_SATELITE:
    
                return "Satelite";
            case MAPTYPE_TERRAIN:
    
                return "Terrain";
            case MAPTYPE_HYBRID:
    
                return "Hybrid";
    
            default:
                return "Normal";
            }
        }
    
        public void zoomWithBounds(LatLngBounds bounds, int padding)
                throws IllegalStateException {
            CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
    
            getMap().animateCamera(cu);
    
        }
    
        public void addLocationPin(Location location) {
            mGoogleMap.addMarker(new MarkerOptions().position(
                    new LatLng(location.getLatitude(), location.getLongitude()))
                    .icon(BitmapDescriptorFactory
                            .defaultMarker(BitmapDescriptorFactory.HUE_RED)));
        }
    
        public void addAddressPin(AddressHolder addressHolder) {
            if (addressHolder.position != null) {
    
                String city = addressHolder.city;
                String address = addressHolder.address;
    
                // address or city or empty
                String title = (address != null && !address.isEmpty()) ? address
                        : ((city != null) ? city : "");
    
                MarkerOptions markerOptions = new MarkerOptions()
                        .position(addressHolder.position)
                        .title(title)
                        .icon(BitmapDescriptorFactory
                                .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
    
                Marker destMarker = mGoogleMap.addMarker(markerOptions);
    
                destMarker.showInfoWindow();
    
                addressPin = addressHolder;
    
            }
        }
    
        public void moveTo(AddressHolder addressHolder) {
    
            GoogleMap map = getMap();
    
            CameraUpdate center = CameraUpdateFactory
                    .newLatLng(addressHolder.position);
    
            CameraUpdate zoom = CameraUpdateFactory.zoomTo(16);
    
            map.moveCamera(center);
            map.animateCamera(zoom);
        }
    
        public void zoomTo(Location location) {
            if (location == null) {
                return;
            }
    
            zoomTo(new LatLng(location.getLatitude(), location.getLongitude()));
        }
    
        public void zoomTo(AddressHolder addressHolder) {
            if (getMap() == null || addressHolder.position == null) {
                Log.e(TAG, "zoomTo map or address position was null: map "
                        + (getMap() == null) + " address position "
                        + (addressHolder.position == null));
                return;
            }
    
            addAddressPin(addressHolder);
    
            // Zoom in, animating the camera.
            zoomTo(addressHolder.position);
    
        }
    
        private void zoomTo(LatLng latlng) {
    
            GoogleMap map = getMap();
    
            if (getMap() == null || latlng == null) {
                return;
            }
    
            // Zoom in, animating the camera.
            map.animateCamera(CameraUpdateFactory.newLatLngZoom(latlng, 16));
        }
    
        public void lookupAddress(final FetchAddressCallback fetchAddressCallback,
                String address, String city) {
    
            new GetAddressPositionTask(fetchAddressCallback, address, city)
                    .execute();
        }
    
        public void lookupAddress(final FetchAddressCallback fetchAddressCallback,
                String searchString) {
    
            new GetAddressPositionTask(fetchAddressCallback, searchString)
                    .execute();
        }
    
        private class GetAddressPositionTask extends
                AsyncTask<String, Integer, AddressHolder> {
    
            private FetchAddressCallback fetchAddressPositionCallback;
    
            private String searchString;
    
            private String city = "";
            private String address = "";
    
            public GetAddressPositionTask(
                    FetchAddressCallback fetchAddressPositionCallback,
                    String address, String city) {
                this.fetchAddressPositionCallback = fetchAddressPositionCallback;
    
                this.city = city;
                this.address = address;
                this.searchString = address + ", " + city;
            }
    
            public GetAddressPositionTask(
                    FetchAddressCallback fetchAddressPositionCallback,
                    String searchString) {
                this.fetchAddressPositionCallback = fetchAddressPositionCallback;
    
                this.searchString = searchString;
            }
    
            @Override protected void onPreExecute() {
                super.onPreExecute();
            }
    
            @Override protected AddressHolder doInBackground(String... params) {
    
                final String lookupStringUriencoded = Uri.encode(searchString);
    
                LatLng position = null;
    
                try {
                    if (geocoder != null) {
                        List<Address> addresses = geocoder.getFromLocationName(
                                searchString, 1);
                        if (addresses != null && !addresses.isEmpty()) {
                            Address first_address = addresses.get(0);
    
                            String foundCity = first_address.getLocality();
    
                            if (foundCity != null) {
                                city = (city.isEmpty()) ? foundCity : city;
                            }
    
                            String addressName = first_address.getThoroughfare();
                            String streetNumber = first_address
                                    .getSubThoroughfare();
    
                            // if (addressName != null && address.isEmpty()) {
                            address = (streetNumber != null) ? addressName + " "
                                    + streetNumber : addressName;
                            // }
                            position = new LatLng(first_address.getLatitude(),
                                    first_address.getLongitude());
                            Log.d(TAG, "geocoder was found " + position);
                        }
                    } else {
                        Log.e(TAG, "geocoder was null, is the module loaded?");
                    }
    
                } catch (IOException e) {
                    // Log.e(TAG, "geocoder failed, moving on to HTTP");
                }
                // try HTTP lookup to the maps API
                if (position == null) {
                    HttpGet httpGet = new HttpGet(
                            "http://maps.google.com/maps/api/geocode/json?address="
                                    + lookupStringUriencoded + "&sensor=true");
                    HttpClient client = new DefaultHttpClient();
                    HttpResponse response;
                    StringBuilder stringBuilder = new StringBuilder();
    
                    try {
                        response = client.execute(httpGet);
                        HttpEntity entity = response.getEntity();
                        InputStream stream = entity.getContent();
                        int b;
                        while ((b = stream.read()) != -1) {
                            stringBuilder.append((char) b);
                        }
                    } catch (ClientProtocolException e) {
                        Log.e(TAG, e.getMessage(), e);
                    } catch (IOException e) {
                        Log.e(TAG, e.getMessage(), e);
                    }
    
                    JSONObject jsonObject = new JSONObject();
                    try {
                        // Log.d("MAPSAPI", stringBuilder.toString());
    
                        jsonObject = new JSONObject(stringBuilder.toString());
                        if (jsonObject.getString("status").equals("OK")) {
                            jsonObject = jsonObject.getJSONArray("results")
                                    .getJSONObject(0);
    
                            JSONArray address_components = jsonObject
                                    .getJSONArray("address_components");
    
                            String jsonCity = "";
                            String jsonAddress = "";
                            String jsonStreetNumber = "";
    
                            // extract looked up address information
                            for (int i = 0; i < address_components.length(); i++) {
                                JSONObject address_component = address_components
                                        .getJSONObject(i);
                                String type = address_component.getJSONArray(
                                        "types").getString(0);
    
                                String value = address_component
                                        .getString("long_name");
    
                                if (type.equals("locality")) {
                                    jsonCity = value;
                                }
    
                                if (type.equals("route")) {
                                    jsonAddress = value;
                                }
    
                                if (type.equals("street_number")) {
                                    jsonStreetNumber = value;
                                }
    
                            }
    
                            Log.d("MAPSAPI", jsonCity + "," + jsonAddress + " "
                                    + jsonStreetNumber);
    
                            city = (city.isEmpty()) ? jsonCity : city;
    
                            address = (address.isEmpty()) ? (jsonAddress + " " + jsonStreetNumber)
                                    .trim() : address;
    
                            // extract position
                            jsonObject = jsonObject.getJSONObject("geometry");
                            jsonObject = jsonObject.getJSONObject("location");
                            String lat = jsonObject.getString("lat");
                            String lng = jsonObject.getString("lng");
    
                            Log.d("MAPSAPI", "latlng " + lat + ", " + lng);
    
                            position = new LatLng(Double.valueOf(lat),
                                    Double.valueOf(lng));
                        }
    
                    } catch (JSONException e) {
                        Log.e(TAG, e.getMessage(), e);
                    }
    
                }
                return new AddressHolder(address, city, position);
            }
    
            @Override protected void onPostExecute(final AddressHolder result) {
                Log.d(TAG, "GetAddressPositionTask " + result);
                if (result.position != null) {
                    fetchAddressPositionCallback.addressFound(result);
                } else {
                    fetchAddressPositionCallback.addressLookupFailed();
                }
                // ensure no more callbacks to this
                fetchAddressPositionCallback = null;
                super.onPostExecute(result);
            }
    
        }
    
    }
    

    我已经在我的应用中实现了Dagger http://square.github.io/dagger/,这解释了@Singleton,这使我能够这样做:

    @Inject GoogleMapsModule googleMapsModule;
    

    每当我想在我的代码中的任何地方使用此对象时。不过,我认为您可以通过扩展应用程序来存储地图数据。例如,您可以阅读此博客:http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/

    要在GoogleMapsModule中保留正确的引用,请执行以下操作:

    @Override public void onMapReady(GoogleMap map) {
        if (map != null) {
            googleMapsModule.setMap(map);
        }
    }
    

    现在,最后一个松散的结局是,如果活动是从头开始而GoogleMapModule持有引用,那么在地图上完成的任何操作都将无效,因为引用不再与地图相关联。为了处理这个问题,如果savedInstanceState为null,我将销毁地图:

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
             ...
        if (savedInstanceState != null) {
             // all is well
            mapsFragment = (GoogleMapFragment) fm
                    .findFragmentByTag(FRAGMENT_MAP_TAG);
        } else {
            // no saved instance - destroy the map to enable onMapReady setting a new reference
            googleMapsModule.destroyMap();
        }
    
        if (device.isMultiPane()) {
            addMapFragment(ft).commit();
        }
    }
    
    // called when the map tab is selected or from onCreate if multipane
    private FragmentTransaction addMapFragment(FragmentTransaction ft) {
        if (mapsFragment == null) {
            AddressHolder address = (device.isMultiPane()) ? null
                    : getSelectedAddressHolder();
            mapsFragment = GoogleMapFragment.newInstance(address);
            ft.add(R.id.details, mapsFragment, Turios.FRAGMENT_MAP_TAG);
    
            mapsOptionsFragment = new GoogleMapOptionsFragment();
            ft.add(R.id.details, mapsOptionsFragment, FRAGMENT_MAP_OPTIONS_TAG);
        } else {
            ft.attach(mapsFragment);
            ft.attach(mapsOptionsFragment);
        }
        return ft;
    }
    

    最后,Android的默认行为是启动一个新的Activity,执行onCreate,每次启动应用程序,或从另一个Activity等移回。因此,我已将manifest中的launchMode设置为singleTask。

        <activity
            android:name=".activities.Turios"
            android:alwaysRetainTaskState="true"
            android:clearTaskOnLaunch="true"
            android:launchMode="singleTask"
             >
    
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
    
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable_address" />
        </activity>
    

    这里解释了Launchmode:http://developer.android.com/guide/topics/manifest/activity-element.html#lmode

答案 1 :(得分:0)

不,没有办法强制地图保留其数据。