Android - 如何更新小部件,但只有在可见时?

时间:2010-03-10 12:24:24

标签: android android-appwidget visible

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

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

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

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

4 个答案:

答案 0 :(得分:17)

要在屏幕关闭时不断更新,请使用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

答案 1 :(得分:10)

  1. 您可以向PowerManager询问isScreenOn()
  2. 您可以注册Intent ACTION_SCREEN_OFF / ACTION_SCREEN_ON并相应地打开/关闭计时器。
  3. 尽管上面关于AlarmManager的答案是正确的,但可能还不够,因为我观察到许多手机即使不是* _WAKEUP类型也会发出警报。如果安装了其他正在唤醒设备的应用程序,则可能会发生这种情况。如果它一旦醒来,它就会发出所有待处理的警报。

答案 2 :(得分:6)

我在一个名为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的答案。虽然它可能不适用于其他第三方发射器。

==更新==

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

答案 3 :(得分:0)

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()种方法,如xandy的回答所引用的here所述。可以通过缓存生成的已安装CATEGORY_HOME应用程序列表并监听ACTION_PACKAGE_ADDED / CHANGED / REMOVED广播来更新它,从而优化那里的想法。

我的策略是:

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