【问题标题】:Waiting for onMapReady() to be called等待 onMapReady() 被调用
【发布时间】:2015-11-08 17:15:22
【问题描述】:

我有一个以通常方式实现的 Google Map,调用 MapFragment 的 getMapAsync(),然后等待调用 onMapReady() 以提供 GoogleMap 实例。这一切正常,直到我添加代码以等待 onMapReady() 被调用,以确保在继续之前 GoogleMap 实例可用。

在 getMapAsync() 返回和 onMapReady() 被调用之间有很短的时间间隔(有道理——否则它不需要是异步的)。虽然在我的非正式测试中,延迟往往不到半秒,但我想处理延迟可能更长的情况。

考虑到这个目标,我添加了一个简单的等待循环来阻塞一个名为“map_ready”的变量。 map_ready 最初是假的,它被 onMapReady() 设置为真。 waitForGoogleMap() 方法简单地循环,定期测试变量并仅在变量为真时返回。这是代码大纲。

    static boolean map_ready = false;

    private void init_gmap_fragment(Activity a) {
        [...]
        MapFragment f_new = new MapFragment();
        [...]
        f_new.getMapAsync(this);
        waitForGoogleMap();
    }

    synchronized private void waitForGoogleMap() {
        while (!map_ready) {
            Log.d(LOGTAG, "Waiting for GoogleMap...");
            try {
                wait(1000);
            } catch (Exception e) { Log.d(LOGTAG, "Exception!"); }
        }
    }

    public void onMapReady(GoogleMap gmap) {
        try {
            this.gmap = gmap;
            map_ready = true;
        }
        [...]
    }

上面显示的代码一遍又一遍地打印出“Waiting for GoogleMap...”——似乎运行 waitForGoogleMap() 会阻止 onMapReady() 被调用。如果我注释掉对 waitForGoogleMap() 的调用,它运行得很好。

我做错了什么?


更新/澄清:我认为我面临的核心问题是我想要侦听一个预计将与侦听器在同一线程上发生的事件。在这种情况下,waitForGoogleMap() 正在等待“onMapReady() 调用”事件,并且两者都在主线程上。

我假设 onMapReady() 之类的回调是通过创建一个工作线程来实现的,该线程完成必要的工作,然后调用主线程的 Handler 将回调(例如 onMapReady())添加到主线程的 MessageQueue .另外,当我从主线程调用 wait() 时,主线程的 looper 将借此机会从其队列中执行另一个项目。

但显然我错了:-)。

底线:如何在 onMapReady() 执行之前阻止?


谢谢, 巴里

附:以上是我的代码的简化版本。实现 OnMapReadyCallback(以及因此的 onMapReady() 回调)的包含类实际上是一个单例。使用 Instance() 方法创建实例,随后通过单独的 getInstance() 方法获取该实例。一旦这工作正常,我将调用 waitForGoogleMap() 到 getInstance() 方法中。这样,应用程序在绝对需要之前不会阻塞。

【问题讨论】:

    标签: android google-maps google-maps-android-api-2


    【解决方案1】:

    我做错了什么?

    waitForGoogleMap() 运行在应该调用onMapReady() 的同一线程上,因此在waitForGoogleMap() 返回之前无法调用onMapReady()

    摆脱waitForGoogleMap()。在onMapReady() 中启动需要GoogleMap 的工作。如果需要,使用事件总线来获得“嘿,地图准备好了!”事件转移到其他组件。

    【讨论】:

    • 感谢您的回答。当然,我已经在 onMapReady() 中完成了必要的工作——那里没有问题。然而,想象一下 onMapReady() 回调在一两分钟内没有发生的场景。主 UI 线程将在 getMapAsync() 调用之后继续运行,并且将快速运行依赖于应该在 onMapReady() 中初始化的内容的代码。发生这种情况时,我想阻止直到实际调用 onMapReady() 。尽管在主线程上调用了 onMapReady(),但我认为由 getMapAsync() 启动的工作将在工作线程上进行。这不正确吗?
    • @BarryHolroyd:“将很快遇到依赖于应该在 onMapReady() 中初始化的东西的代码”——那么您的应用程序就会遇到基本的架构问题。 “我想阻止直到实际调用 onMapReady()”——这将成功冻结你的 UI 并在大约 5 秒内触发 ANR。它还会让用户想知道为什么你的应用程序有问题。 “这不正确吗?” -- getMapAsync() 在主应用程序线程上调用。除非另有说明,否则一切都会在主应用程序线程上调用。
    • @BarryHolroyd:如果在地图准备好之前您不能允许用户执行某些操作,请在 onMapReady() 内部之前不要启用这些选项。在此期间使用进度指示器等,允许用户访问您的应用程序中还不需要地图的其他部分。
    • 好的cmets,谢谢。我开始意识到这一点。我认为我的架构非常合理。问题是我的应用程序是 100% 地图驱动的——事实上,这正是它与众不同的地方。用户从一张空白地图开始,唯一可以采取的有趣步骤需要地图。我不太担心 ANR —— 我会在第二秒左右检查并更新用户,而不是无休止地等待。我想我可以对用户做某事的每一次尝试做出反应,但我宁愿有一个进度指示器(如你所建议的那样),指示应用程序正在等待 Gmap 服务。
    • 仍然不确定为什么我的方法不起作用。在我看来,looper 应该在它最终执行时运行 onMapReady() ;如果是这样,我可以让用户了解状态(“正在等待 Google 地图服务...”),如果在合理的时间内没有响应,最终会显示适当的消息超时。
    猜你喜欢
    • 1970-01-01
    • 2021-01-25
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多