【问题标题】:How best to re-create markers/polylines when phone is rotated (orientation change)旋转手机时如何最好地重新创建标记/多段线(方向更改)
【发布时间】:2013-06-03 17:34:51
【问题描述】:

背景:

  • 开发使用 Android Google Map v2 的原生 Android 应用程序,使用 android.support.v4.app.FragmentActivity。在 Android v2.2 上运行。

目标:

  • 在更改手机方向之前保留地图上“绘制”的标记/多段线。

问题:

  1. 我能否将标记/折线“保存”为捆绑包的一部分,并通过使用适当的savedInstance.put.. 方法将它们保存在onSaveInstanceState 中,然后使用适当的方法将它们“恢复”到onCreate 中,从而重新显示它们适当的savedInstanceState.get.. 方法。

    在查看标记 getID() 的描述时,当 Marker.getId() method 的 Google 文档指出以下内容时,我感到很困惑:

    从 Bundle 中恢复地图时,该地图上的标记也会恢复。但是,这些标记随后将由不同的 Marker 对象表示。标记的 id 可用于在此类恢复后检索标记对象的新实例。

    Google 文档(上面的粗体文本)听起来好像 Marker 只是自动恢复而无需采取任何操作。那不是我的经验……也许我误解了所陈述的内容。或者,也许您必须在 Bundle 中明确保存地图?有人能澄清一下这是什么意思吗?

  2. 假设我必须通过适当的 savedInstance.put... 方法将标记和折线显式保存到包中,我应该保存整个标记还是应该保存标记 ID 并使用标记 ID 检索标记信息以重新显示标记?我找不到可以让我保存整个标记的 put 方法。

    我注意到 Google Maps Android API v2 的 MapFragment section 声明如下:

    从 GoogleMap 获得的任何对象都与视图相关联。重要的是不要抓住超出视图生命周期的对象(例如标记)。否则会导致视图无法释放,导致内存泄漏。

    这句话让我相信我不应该尝试保存标记本身,而是尝试保存标记 ID,然后根据与标记 ID 关联的标记对象重新生成标记。对于折线也是如此。我的假设正确吗?

  3. 另外,我应该避免将标记作为类变量吗?我担心的是,如果 Marker 是一个类变量并且 Activity Map 片段放置在后堆栈上,这可能会导致内存泄漏,因为它会有效地“保持对象”,如上述文档中所述。这是我应该关心的事情吗?

问候。

【问题讨论】:

    标签: android android-maps-v2


    【解决方案1】:

    我是否可以将标记/折线“保存”为捆绑包的一部分,并通过使用适当的“savedInstance.put..”方法将它们保存在 onSaveInstanceState 中来重新显示它们,然后在 onCreate 中使用“恢复”它们适当的“savedInstanceState.get..”方法。

    没有。

    Google 文档(上面的粗体文本)听起来好像 Marker 只是自动恢复而无需采取任何操作。那不是我的经验……也许我误解了所陈述的内容。或者,也许您必须在 Bundle 中明确保存地图?有人能澄清一下这是什么意思吗?

    您没有误解任何内容。文档不正确。

    我应该保存标记 ID 并使用标记 ID 检索标记信息以重新显示标记

    标记 ID 在配置更改时不是永久性的 - 它取决于创建可视对象的顺序(第一次调用 addMarker 返回 ID 为“m1”的对象,第二个是“m2”)。您不能以任何方式使用此值(从 API 版本 3.1.36 开始),恕我直言,它的存在确实没有意义。我实际上已经总结了an issue related to ID。至少应该有一个函数GoogleMap.getMarkerById(String) 用于Marker.getId() 没有什么意义。

    3) 另外,我应该避免将标记作为类变量吗?我担心的是,如果 Marker 是一个类变量并且 Activity Map 片段放置在后堆栈上,这可能会导致内存泄漏,因为它会有效地“保持对象”,如上述文档中所述。这是我应该关心的事情吗?

    是的。保持对Marker 或任何其他可视对象的静态引用会导致泄漏。


    并不是说回答你所有的问题和疑虑就能更接近解决方案,所以这是我的建议。

    我假设您有一个数据集,MarkersPolylines 是从中创建的,并且可能在从 Web 服务获取后将其存储在 DB 中。现在,如果您从Activity 中的AsyncTask 中的DB 加载它,或者甚至不将其存储在DB 中,而只直接在Activity 中获取 - 这很糟糕。

    尽量让您的数据可访问,因此只需在进程终止后(或在内存不足时将其删除后)将其重新加载到内存中。如果你这样做 - 那很好。当然不是全部:如果你有 20000 个标记并且每个标记都显示在信息窗口上,它可以等待......

    现在您已经拥有了在内存中创建标记所需的所有数据,只需像第一次那样创建它们即可。不需要额外的代码。

    我们可以争论这是好主意还是坏主意,我会改进答案,但这需要有关上下文的更多信息:

    • 标记和折线的数量
    • 您还有哪些额外数据
    • 你的模型放在哪里

    当然还有另一种方式:您可以在onSaveInstanceState 中发送MarkerOptions。如果您保持最新,或者如果您的Markers 没有更改并且数量不多,这可能对您有用。我无法理解每次旋转时通过 IPC 发送数千个对象或按下 HOME 按钮。

    【讨论】:

    • 谢谢你,Macie...只是澄清什么可以做什么不能做什么是非常有帮助的。希望有人针对 Google 文档提出了问题。
    • 作为背景...我在这里只有一个我担心的标记和连接到这个标记的两条折线。标记表示用户在屏幕上点击的位置 (tapMarker)。第一条折线将用户当前的 GPS 连接连接到 tapMarker,第二条折线将点击标记连接到指定的 LatLng。指定 LatLng 的数据将存储在数据库中。
    • 在这种情况下,您只需将水龙头的LatLng 发送到onSaveInstanceState。这是有道理的,因为它是用户活动(就像编辑文本字段一样)。可选两个ArrayList<LatLng> 重新创建折线。我认为我的回答会更有用;)
    • 你的回答很有用!现在我知道什么是可能的,什么是不可能的。谢谢!
    • 有一个Marker.getId() 实例方法在onInfoWindowClick(Marker m) 这样的情况下很有用。例如,您可以找到对应的具有id的数据对象。
    【解决方案2】:

    在我看来,在保存地图的片段上调用setRetainInstance(true); 可以通过暂停、方向更改等保留地图上的所有内容,而不必担心设置和获取。这不是推荐的方法有什么原因吗?

    【讨论】:

    • 我可以确认它工作正常!就是这么简单。为什么这篇文章没有被标记为答案?
    • 如果您的地图片段嵌套在另一个片段中,则它不起作用。你得到一个运行时异常。
    • 那么如果在两个片段上都设置了RetainInstance 会发生什么? (对不起,远离测试环境但仍然好奇)
    • 你的救星!我花了整个周末研究 Android 中的 Activity Lifecycles、Bundles、Parcels、Parcelable 接口和 IPC……但无济于事。我只需要一行代码来保存我的状态。
    • 有没有办法在方向改变时添加回调函数?我试过 onConfigurationChanged 但这会使应用程序崩溃,因为我认为 GoogleMap 还没有准备好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-29
    相关资源
    最近更新 更多