【问题标题】:NotificationManager.notify locks the phone and EmulatorNotificationManager.notify 锁定手机和模拟器
【发布时间】:2012-11-10 16:41:26
【问题描述】:

问题:

手机/模拟器会锁定重复的通知更新。让模拟器在锁定后恢复响应的唯一方法是按给定顺序按 Home => Menu => Lock => Home => Menu Button。

代码:

通知推送代码:

        // Set up notifcation views
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Get notification manager
        RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.service_notification);
        contentView.setViewVisibility(R.id.current_error_text, View.GONE);
        contentView.setViewVisibility(R.id.error_text, View.GONE);
        contentView.setViewVisibility(R.id.info_error_text, View.GONE);
        contentView.setViewVisibility(R.id.info_text, View.GONE);
        contentView.setViewVisibility(R.id.next_check_in_text, View.VISIBLE);
        contentView.setViewVisibility(R.id.current_profile_text, View.VISIBLE);
        contentView.setViewVisibility(R.id.profile_name_text, View.VISIBLE);
        contentView.setTextViewText(R.id.next_check_in_text, mainText);
        // Set profile text now
        contentView.setTextViewText(R.id.profile_name_text, miniText);
        // Set up a new notification
        Notification notif = new Notification(R.drawable.service_logo_small, "Service is running", System.currentTimeMillis());
        notif.contentView = contentView; // Set content view
        // Create and plug in the PendingIntent
        Intent notifIntent = new Intent(this, EntryPointActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0, notifIntent, 0); // Set up the Pending Intent
        notif.contentIntent = pIntent;
        // Now set up notification flags
        notif.flags |= Notification.FLAG_NO_CLEAR;
        notif.flags |= Notification.FLAG_ONGOING_EVENT;
        notif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
        if(sp.getBoolean("UpdateLights", true)) notif.flags |= Notification.DEFAULT_LIGHTS;
        if(sp.getBoolean("UpdateVibrate", true)) notif.flags |= Notification.DEFAULT_VIBRATE;
        if(sp.getBoolean("UpdateSound", true)) notif.flags |= Notification.DEFAULT_SOUND;

        notificationManager.notify(R.string.app_name, notif);

所有对象都存在并且项目编译完美。我没有遇到 NullPointerExceptions!

调用通知创建函数的代码:

final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
@Override
public void run() {
    if(( nextUpdateIn - System.currentTimeMillis() ) > 0) {
        long milliseconds = (nextUpdateIn - System.currentTimeMillis());
        int seconds = (int) (milliseconds / 1000) % 60 ;
        int minutes = (int) ((milliseconds / (1000*60)) % 60);
        String toShow = "Next Check In: " + minutes + " minute" + ((minutes != 1) ? "s" : "") + " " + seconds + " second" + ((seconds != 1) ? "s" : "");
        pushNotification(STATE_LOADEDSUCCESSFULLY, currentProfile.getProfileName(), toShow);
    } else {
        currentState = STATE_RELOADING;
        pushNotification(STATE_RELOADING, null, "Refreshing..");
        timer.cancel();
    }
}
}, 1, 999);

同样,所有对象都存在! 在上述过程中通知已更新,但如上所述,它锁定了模拟器和手机

目标:

更新状态栏中的通知以基本上显示倒计时,直到下次刷新。

请帮我尽快解决这个错误!

提前致谢:)

问候,

阿克希特·苏塔

编辑:

我正在尝试通过 SERVICE 运行此代码,并且我已经在运行 Android 2.2、2.3.3、4.1 的模拟器上进行了尝试,它们都给了我同样的问题!

【问题讨论】:

  • 您可以尝试增加计时器的时间来检查重复推送通知是否导致问题。我有一个类似的情况,我错误地将周期设置为 300ms ,这导致应用程序冻结。

标签: android android-notifications


【解决方案1】:

您用于显示和更新通知的代码运行良好。

在我看来,唯一的原因可能是同时构建了许多计时器。由于初始延迟为 1 毫秒,因此如果通过某些意外循环调用 timer.scheduleAtFixedRate(),您可能会使用数百个通知更新锁定系统。我建议在该行放置一个断点并找出发生这种情况的原因。

我还有两个建议:

  1. 请记住,Notification 构造函数现已弃用,您可能应该考虑使用通知生成器,例如 Jake Wharton 的 NotificationCompat2
  2. 建议使用ScheduledThreadPoolExecutor 而不是Timer

【讨论】:

  • 我已经尝试了第二个建议,但我仍然面临同样的问题。代码位于:pastebin.com/dfysMRzb。关于第一个建议,我仍在使用 Gingerbread API,所以我猜它在这些 API 中还没有贬值!
  • 何时调用stpe.scheduleAtFixedRate()?它应该只启动一次。完成后请务必将其关闭。
  • pastebin.com/dfysMRzb:这是在程序中运行的确切代码块。它被调用一次,您也可以查看关闭和 scheduleAtFixedRate() 代码!
  • isShutdown 在您的 sn-p 中将始终为 false。我实际上看不到 scheduleAtFixedRate() 正在执行的位置,并且真诚地认为这是造成您问题的原因。
  • 感谢您发布您的决议。我碰巧在 Jelly Bean 上遇到了一个相关问题,导致正在进行的通知动画退出和返回,因为我正在重新创建它而不是更新现有实例。
【解决方案2】:

我同意@Paul Lammertsma 的观点,假设您的代码会产生很大的负载。但是,每 999 毫秒执行一次计时器任务不会有问题,我想问题出在您的“通知推送代码”中。无论如何,您应该使用method profiling 来确定瓶颈是什么。

附:我认为,您的代码中有一个小错误:

if (( nextUpdateIn - System.currentTimeMillis() ) > 0) {
    long milliseconds = (nextUpdateIn - System.currentTimeMillis());
    // milliseconds may still be negative here
    ...

你可能想要这个:

long milliseconds = nextUpdateIn - System.currentTimeMillis();
if (milliseconds > 0) {
    ...

附言为什么要使用Notification.FLAG_FOREGROUND_SERVICE 标志?

【讨论】:

  • 如果Timer.scheduleAtFixedRate() 在循环中执行,无限的新计时器将创建初始延迟为 1 毫秒的通知,而不是随后的 999 毫秒延迟。否则,我同意你的观点。
【解决方案3】:

嗯,我终于知道问题出在哪里了。

您可能也对此链接感兴趣:http://code.google.com/p/android/issues/detail?id=13941#c12

所以,根据上面的链接,我停止在每次调用通知推送功能时创建一个新的 Notification 对象。现在,我创建了一次对象并继续重复使用它!这已经停止了模拟器锁定!

以下是通知推送代码的修改:

    // Set up notifcation views
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.service_notification);
    contentView.setViewVisibility(R.id.current_error_text, View.GONE);
    contentView.setViewVisibility(R.id.error_text, View.GONE);
    contentView.setViewVisibility(R.id.info_error_text, View.GONE);
    contentView.setViewVisibility(R.id.info_text, View.GONE);
    contentView.setViewVisibility(R.id.next_check_in_text, View.VISIBLE);
    contentView.setViewVisibility(R.id.current_profile_text, View.VISIBLE);
    contentView.setViewVisibility(R.id.profile_name_text, View.VISIBLE);
    contentView.setTextViewText(R.id.next_check_in_text, mainText);
    // Set profile text now
    contentView.setTextViewText(R.id.profile_name_text, miniText);
    // Set up a new notification
    notif.contentView = contentView; // Set content view
    // Create and plug in the PendingIntent
    Intent notifIntent = new Intent(this, EntryPointActivity.class);
    PendingIntent pIntent = PendingIntent.getActivity(this, 0, notifIntent, 0); // Set up the Pending Intent
    notif.contentIntent = pIntent;
    // Now set up notification flags
    notif.flags |= Notification.FLAG_NO_CLEAR;
    notif.flags |= Notification.FLAG_ONGOING_EVENT;
    notif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
    if(sp.getBoolean("UpdateLights", true)) notif.flags |= Notification.DEFAULT_LIGHTS;
    if(sp.getBoolean("UpdateVibrate", true)) notif.flags |= Notification.DEFAULT_VIBRATE;
    if(sp.getBoolean("UpdateSound", true)) notif.flags |= Notification.DEFAULT_SOUND;

    notificationManager.notify(R.string.app_name, notif);

您可能会看到 NotificationManagerNotification 不再在通知推送代码中创建。

以下是我对计时器所做的更改:

NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Get notification manager
Notification notif = new Notification(R.drawable.service_logo_small, "Service is running", System.currentTimeMillis());
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
@Override
public void run() {
    if(( nextUpdateIn - System.currentTimeMillis() ) > 0) {
        long milliseconds = (nextUpdateIn - System.currentTimeMillis());
        int seconds = (int) (milliseconds / 1000) % 60 ;
        int minutes = (int) ((milliseconds / (1000*60)) % 60);
        String toShow = "Next Check In: " + minutes + " minute" + ((minutes != 1) ? "s" : "") + " " + seconds + " second" + ((seconds != 1) ? "s" : "");
        pushNotification(STATE_LOADEDSUCCESSFULLY, currentProfile.getProfileName(), toShow);
    } else {
        currentState = STATE_RELOADING;
        pushNotification(STATE_RELOADING, null, "Refreshing..");
        timer.cancel();
    }
}
}, 1, 999);

如您所见,我在计时器中重用了对象 notificationManagernotif,因此 CPU 不会负担每次重新创建 Notification 对象的负担正在执行计时器。

因此,通过上述代码更改,我的代码现在可以完美运行!

谢谢你帮助我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-15
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多