【问题标题】:Android - how update widget often but only when it is visible?Android - 如何经常更新小部件但仅在它可见时?
【发布时间】:2010-03-10 12:24:24
【问题描述】:

我将创建需要每分钟更新其内容的小部件(它显示与时间相关的数据)。

但是,如果小部件当前不可见,则无需更新小部件,这意味着:

  • 屏幕已关闭
  • 另一个应用程序正在运行
  • 小部件被放置在另一个(不可见的)主屏幕选项卡上

每分钟只更新可见小部件的最佳方法是什么 - 无需唤醒设备或进行不必要的计算?小部件变得可见后,更新前的小延迟是可以接受的。

【问题讨论】:

    标签: android android-appwidget visible


    【解决方案1】:

    为避免在屏幕关闭时更新,请使用AlarmManager 安排不会唤醒手机的重复闹钟。

    您的问题中的其他两个要点是不可能的。无法检测您的小部件是否位于当前不可见的主屏幕上,也无法确定是否正在运行隐藏主屏幕的应用程序。我已在http://b.android.com 上提交了一张票,要求将此功能添加到 Android。如果你想主演它,它会帮助它获得优先权:http://code.google.com/p/android/issues/detail?id=5529&q=reporter:mark.r.baird&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

    【讨论】:

    • 我出演了,至少这个我能做到,你回答了我这么多问题,而且以后可能还会这样。谢谢。
    • 已加星标,太糟糕了,它不会在当前使用的数百万个 hadset 中可用...
    • 可以判断当前运行的是哪个app:ActivityManager mAM = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);列出 任务=mAM.getRunningTasks(1);
    • @htafoya 不,这可能意味着 Google 的某个人在问题跟踪器中负责春季大扫除,并在 3 月 15 日与其他 535 人一起关闭了此任务:code.google.com/p/android/issues/…
    • @catalyst294 这种方法的问题是 updatePeriodMillis 的最小值是 30 分钟,一些小部件需要更小的更新间隔。
    【解决方案2】:
    1. 你可以向 PowerManager 询问 isScreenOn()
    2. 您可以注册 Intent ACTION_SCREEN_OFF/ACTION_SCREEN_ON 并相应地打开/关闭计时器。

    尽管上面关于 AlarmManager 的答案是正确的,但这可能还不够,因为我观察到许多电话也会发出警报,即使它们不是 *_WAKEUP 类型。如果安装了其他正在唤醒设备的应用程序,则可能会发生这种情况。如果它一旦被唤醒,它就会传递所有未决的警报。

    【讨论】:

    • 这是很重要的一点。如this thread 中所述,即使屏幕处于睡眠状态,警报也可能触发。
    • 我还注意到,在打开开发者模式(并将内容记录到 logcat)时,设备会保持唤醒状态。为了测试在没有开发模式的情况下它会做什么,我添加了一个计数器,用于显示在小部件上的所有更新,并注意到在关闭开发模式时它会进入睡眠状态,并且不会使用 AlarmManager.RTC 事件更新小部件。我找不到任何文档来证明开发者模式保持唤醒状态,但这对我来说确实有意义。
    【解决方案3】:

    我在一个名为 24clock in goole code 的项目下找到了这个。当用户不在家时,它会尝试不更新小部件:

        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    
        List<RunningTaskInfo> runningTasks = am.getRunningTasks(2);
        for (RunningTaskInfo t : runningTasks) {
            if (t != null && t.numRunning > 0) {
                ComponentName cn = t.baseActivity;
                if (cn == null) continue;
    
                String clz = cn.getClassName();
                String pkg = cn.getPackageName();
    
                // TODO make this configurable
                if (pkg != null && pkg.startsWith("com.android.launcher")) {
                    return true;
                }
    
                return false;
            }
        }
    

    这可能是您要求 2 的答案。虽然它可能无法在其他 3rd 方启动器下工作。

    == 更新 ==

    几个月后,我突然想到了如何检测主屏幕是否正在显示。我把它放在我的blog 中,我对我的 Desire 进行了测试,它运行良好。方法是在Android中查询所有已安装的包,其中一个包含“Launcher”能力,然后检查它是否在运行堆栈的顶部。如果有人测试过,也请告诉我结果,因为我无法访问其他 Android 设备。

    【讨论】:

    • 当在非标准主屏幕上运行时,这肯定会失败吗?
    • 请查看我的更新答案,我有一个更好的方法,应该适用于第 3 方。
    【解决方案4】:

    mbaird 接受的答案一针见血。建议的onVisivilityChange() 方法如果实施,应该涵盖上述所有情况。

    与此同时,对于某些类型的小部件来说,这仍然是一个真正的问题。 jom 引入了注册以接收 ACTION_SCREEN_OFF/ACTION_SCREEN_ON 意图的可能性。这很有用,因为依赖非唤醒重复警报是不够的,因为其他服务会导致唤醒。这很困难,因为无法通过 AndroidManifest.xml 订阅此类操作,并且不允许 AppWidgetProvider 调用context.registerReceiver()。这些问题在其他几个 StackOverflow 问题中进行了讨论,包括 Listening for ACTION_SCREEN_OFFandroid.intent.action.SCREEN_ON doesn't work as a receiver intent filterAndroid - how to receive broadcast intents ACTION_SCREEN_ON/OFF?

    通过创建一个附属的BroascastReceiver 实例并使用context.getApplicationContext().registerReceiver() 注册它,我已成功订阅小部件中的 ACTION_SCREEN_OFF/ACTION_SCREEN_ON 意图。这很可能是作弊,至少在随后的某些 Android 版本中,可能会在注册阶段失败,或者事件可能根本无法交付。我已经编写了代码来处理这些情况,但现在它可以工作了。当然,不幸的是,如果应用程序被终止,这将失败。

    另一种可能性是使用isHomeScreenShowing() 之类的方法,如here 所述,xandy 的答案引用了该方法。可以通过缓存生成的已安装CATEGORY_HOME 应用程序列表并收听 ACTION_PACKAGE_ADDED/CHANGED/REMOVED 广播来更新它来优化那里的想法。

    我的策略是:

    • 尽量避免在不可见时被呼叫(通过重复警报)。
    • 调用时,请先检查屏幕状态和其他可见性指标,然后再进行任何昂贵的操作。
    • 然后才调用IntentService 来处理相对昂贵的工作,其中包括持久的网络连接。这对于近乎实时地监控远程服务的状态是必要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-14
      • 2021-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多