在旋转和背部恢复谷歌地图(V2)的地图状态(位置和标记)(图形页面中的片段) [英] Restoring map state (position and markers) of Google Maps (V2) on rotate and on back (MapView in Fragment)

查看:133
本文介绍了在旋转和背部恢复谷歌地图(V2)的地图状态(位置和标记)(图形页面中的片段)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我有一个更大的应用程序中,我有/有几个问题,新的谷歌地图API。我试着来形容它<一个href="http://stackoverflow.com/questions/16171619/markers-disapearing-from-mapview-v2-in-fragment-on-back">in一个不同的问题但因为它似乎太复杂,我决定开始一个新的项目,越简单越好,并尝试重现问题。所以在这儿呢。

I have a larger application in which I had/have several problems with new Google Maps API. I tried to describe it in a different question but since it seems too complex I decided to start a new project, as simple as possible and try to reproduce problems. So here it is.

情况

我用片段,并希望把图形页面里面。我不想使用 MapFragment 。示例项目我prepared可能不是很漂亮,但我试图使它尽可能简单,它必须包含原始应用程序的一些元素(再次简化)。 我有一个活动和我的自定义片段图形页面的它补充说编程。该地图包含一些点/ 标记。点击一个标记信息窗口显示,点击它会导致下一片段正在显示的内容(与更换()函数)。

I'm using Fragments and want to put MapView inside. I don't want to use MapFragment. The sample project I prepared may be not very beautiful but I tried to make it as simple as possible and it had to contain some elements (again simplified) from the original app. I have one Activity and my custom Fragment with MapView in it, added programatically. The Map contains some points/Markers. After clicking on a Marker the InfoWindow is shown and clicking on it causes next Fragment being shown (with replace() function) in content.

的问题

有两个问题我有:

  1. 地图标记显示屏幕旋转的原因类不我的自定义解组错误 MyMapPoint 上课的时候​​发现了 - 我不知道为什么,什么意思

  1. When the Map with Markers is displayed screen rotation causes Class not found when unmarshalling error with my custom MyMapPoint class - I have no idea why and what it means.

我点击标记然后信息窗口。在此之后我preSS硬件后退按钮。现在我可以看到地图,但没有标记并集中在 0,0 点。

I click the Marker and then InfoWindow. After this I press hardware back button. Now I can see the Map but with no Markers and centered in 0,0 point.

的code

MainActivity

MainActivity

public class MainActivity extends FragmentActivity {

    private ArrayList<MyMapPoint> mPoints = new ArrayList<MyMapPoint>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     

        if (savedInstanceState == null) {
            mPoints.add(new MyMapPoint(1, new LatLng(20, 10), 
                "test point", "description", null));            
            mPoints.add(new MyMapPoint(2, new LatLng(10, 20), 
                "test point 2", "second description", null));

            Fragment fragment = MyMapFragment.newInstance(mPoints);
            getSupportFragmentManager().beginTransaction()
                .add(R.id.contentPane, fragment).commit();
        }
    }
}

activity_main.xml

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/contentPane"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

map_fragment.xml

map_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.google.android.gms.maps.MapView
        xmlns:map="http://schemas.android.com/apk/res-auto"
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MyMapFragment

MyMapFragment

public class MyMapFragment extends Fragment implements
    OnInfoWindowClickListener {

    public static final String KEY_POINTS = "points";

    private MapView mMapView;
    private GoogleMap mMap;
    private HashMap<MyMapPoint, Marker> mPoints = 
        new HashMap<MyMapPoint, Marker>();

    public static MyMapFragment newInstance(ArrayList<MyMapPoint> points) {
        MyMapFragment fragment = new MyMapFragment();
        Bundle args = new Bundle();
        args.putParcelableArrayList(KEY_POINTS, points);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mMapView.onSaveInstanceState(outState);
        MyMapPoint[] points = mPoints.keySet().toArray(
            new MyMapPoint[mPoints.size()]);
        outState.putParcelableArray(KEY_POINTS, points);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            Bundle extras = getArguments();
            if ((extras != null) && extras.containsKey(KEY_POINTS)) {
                for (Parcelable pointP : extras.getParcelableArrayList(KEY_POINTS)) {
                    mPoints.put((MyMapPoint) pointP, null);
                }
            }
        } else {
            MyMapPoint[] points = (MyMapPoint[]) savedInstanceState
                .getParcelableArray(KEY_POINTS);
            for (MyMapPoint point : points) {
                mPoints.put(point, null);
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, 
        ViewGroup container, Bundle savedInstanceState) {
        View layout = inflater.inflate(R.layout.map_fragment, container, false);
        mMapView = (MapView) layout.findViewById(R.id.map);
        return layout;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mMapView.onCreate(savedInstanceState);
        setUpMapIfNeeded();
        addMapPoints();
    }

    @Override
    public void onPause() {
        mMapView.onPause();
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        setUpMapIfNeeded();
        mMapView.onResume();
    }

    @Override
    public void onDestroy() {
        mMapView.onDestroy();
        super.onDestroy();
    }

    public void onLowMemory() {
        super.onLowMemory();
        mMapView.onLowMemory();
    };

    private void setUpMapIfNeeded() {
        if (mMap == null) {
            mMap = ((MapView) getView().findViewById(R.id.map)).getMap();
            if (mMap != null) {
                setUpMap();
            }
        }
    }

    private void setUpMap() {
        mMap.setOnInfoWindowClickListener(this);
        addMapPoints();
    }

    private void addMapPoints() {
        if (mMap != null) {
            HashMap<MyMapPoint, Marker> toAdd = 
                new HashMap<MyMapPoint, Marker>();
            for (Entry<MyMapPoint, Marker> entry : mPoints.entrySet()) {
                Marker marker = entry.getValue();
                if (marker == null) {
                    MyMapPoint point = entry.getKey();
                    marker = mMap.addMarker(point.getMarkerOptions());
                    toAdd.put(point, marker);
                }
            }
            mPoints.putAll(toAdd);
        }
    }

    @Override
    public void onInfoWindowClick(Marker marker) {
        Fragment fragment = DetailsFragment.newInstance();
        getActivity().getSupportFragmentManager().beginTransaction()
            .replace(R.id.contentPane, fragment)
            .addToBackStack(null).commit();
    }

    public static class MyMapPoint implements Parcelable {
        private static final int CONTENTS_DESCR = 1;

        public int objectId;
        public LatLng latLng;
        public String title;
        public String snippet;

        public MyMapPoint(int oId, LatLng point, 
            String infoTitle, String infoSnippet, String infoImageUrl) {
            objectId = oId;
            latLng = point;
            title = infoTitle;
            snippet = infoSnippet;
        }

        public MyMapPoint(Parcel in) {
            objectId = in.readInt();
            latLng = in.readParcelable(LatLng.class.getClassLoader());
            title = in.readString();
            snippet = in.readString();
        }

        public MarkerOptions getMarkerOptions() {
            return new MarkerOptions().position(latLng)
                .title(title).snippet(snippet);
        }

        @Override
        public int describeContents() {
            return CONTENTS_DESCR;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(objectId);
            dest.writeParcelable(latLng, 0);
            dest.writeString(title);
            dest.writeString(snippet);
        }

        public static final Parcelable.Creator<MyMapPoint> CREATOR = 
            new Parcelable.Creator<MyMapPoint>() {
            public MyMapPoint createFromParcel(Parcel in) {
                return new MyMapPoint(in);
            }

            public MyMapPoint[] newArray(int size) {
                return new MyMapPoint[size];
            }
        };

    }
}

如果你需要看看任何其他文件 - 让我知道。 这里你可以找到一个完整的项目,你就必须把自己的地图API密钥 AndroidManifest的.xml 文件。

If you need to take a look at any other file - let me know. Here you can find a complete project, you just have to put your own Maps API KEY in AndroidManifest.xml file.

修改

我设法让这个例子更简单,更新了code以上。

I managed to make the example even more simple and updated the code above.

推荐答案

下面是我的修复程序的第一个问题:

Here is my fix to the first problem:

看来,地图正在尝试unparcel所有的包,而不仅仅是它的时候我叫 mMap.onCreate(savedInstanceState)<自己的信息/ code>,它有问题,如果我用我的自定义 Parcelable 类。这为我工作的溶液从 savedInstanceState 删除我的演员,只要我用他们 - 之前,我打电话地图的的onCreate()。我做它 savedInstanceState.remove(MY_KEY)。另一件事我所要做的就是打电话给 mMap.onSaveInstanceState()添加自己的信息 outState 之前片段的 的onSaveInstanceState(包outState)的功能。

It seems that Map is trying to unparcel all the bundle, not just it's own information when I call mMap.onCreate(savedInstanceState) and it has problem with it if I'm using my custom Parcelable class. The solution that worked for me was removing my extras from savedInstanceState as soon as I used them - before I call Map's onCreate(). I do it with savedInstanceState.remove(MY_KEY). Another thing I had to do was to call mMap.onSaveInstanceState() before adding my own information to outState in Fragment's onSaveInstanceState(Bundle outState) function.

这就是我如何处理第二个:

And here's how I handled the second one:

我简单的示例项目到裸露的骨头。我加入原标记来映射,如果我与另一个地图替换片段再单击了背我仍然有调零的地图。 所以,我做了两件事:

I simplified the example project to the bare bones. I was adding raw Markers to the map and if I replace the Fragment with map with another one then after clicking "back" I still got "nulled" map. So I did two things:

  1. 节约 CameraPosition 的onPause()功能在 onResume其恢复()
  2. MMAP 的onPause设置为空()所以当片段返回时,标记再次由 addMapPoints()函数添加(我不得不改变它一点点,因为我是保存和检查标记的id)。
  1. saving CameraPosition in onPause() function to restore it in onResume()
  2. setting mMap to null in onPause() so when the Fragment comes back, the Markers are added again by the addMapPoints() function (I had to change it a little bit since I was saving and checking Markers id's).

下面是code样品:<​​/ P>

Here are code samples:

private CameraPosition cp;

...

public void onPause() {
    mMapView.onPause();
    super.onPause();

    cp = mMap.getCameraPosition();
    mMap = null;
}

...

public void onResume() {
    super.onResume();
    setUpMapIfNeeded();
    mMapView.onResume();
    if (cp != null) {
        mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cp));
        cp = null;
    }
}

和更新 onResume摄像机的位置()我不得不手动初始化地图。我做到了 setUpMap()

And to update the camera position in onResume() I had to manually initialize maps. I did it in setUpMap():

private void setUpMap() {
    try {
        MapsInitializer.initialize(getActivity());
    } catch (GooglePlayServicesNotAvailableException e) {
    }
    mMap.setOnInfoWindowClickListener(this);
    mMap.setOnMapLongClickListener(this);
    addMapPoints();
}

我认识到,这些都不是真正的解决方案 - 只是覆盖,但它是最好的,我可以现在做的项目必须继续下去。如果有人发现清洁修复我会感谢你让我了解他们。

I realize that those aren't real solutions - just overrides but it's the best I can do for now and the project must go on. If anyone finds cleaner fixes I'll be grateful for letting me know about them.

这篇关于在旋转和背部恢复谷歌地图(V2)的地图状态(位置和标记)(图形页面中的片段)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆