5

問題:

電話/エミュレーターは、通知の更新が繰り返されるとロックされます。ロックされた後にエミュレータを応答状態に戻す唯一の方法は、ホーム=>メニュー=>ロック=>ホーム=>メニューボタンを指定された順序で押すことです。

コード:

通知プッシュコード:

        // 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);

繰り返しますが、すべてのオブジェクトが存在します!通知は上記のプロセスで更新されますが、上記のようにエミュレータと電話の両方がロックされます。

標的:

ステータスバーの通知を更新して、基本的に次の更新までのカウントダウンを表示します。

このエラーをできるだけ早く取り除くのを手伝ってください!

前もって感謝します :)

よろしく、

Akshit Soota

編集:

このコードをSERVICE経由で実行しようとしていますが、Android 2.2、2.3.3、4.1を実行しているエミュレーターを試してみましたが、すべて同じ問題が発生します。

4

3 に答える 3

2

通知を表示および更新するためのコードは問題なく機能します。

これの唯一の原因は、多くのタイマーが同時に構築されていることだと私には思えます。timer.scheduleAtFixedRate()初期遅延は 1 ミリ秒であるため、意図しないループによって が呼び出された場合、何百もの通知更新でシステムがロックされる可能性があります。その行にブレークポイントを配置し、なぜそれが起こっているのかを理解することをお勧めします。

追加の提案が 2 つあります。

  1. Notificationコンストラクターは非推奨になっていることに注意してください。おそらく、Jake Wharton の NotificationCompat2 などの通知ビルダーの使用を検討する必要があります
  2. ScheduledThreadPoolExecutorの代わりに使用することをお勧めしますTimer
于 2012-11-14T10:14:05.450 に答える
2

あなたのコードが大きな負荷を生み出すと仮定して、@Paul Lammertsmaに同意します。ただし、タイマー タスクを 999 ミリ秒ごとに実行しても問題はありません。問題は「通知プッシュ コード」にあると思います。とにかく、ボトルネックを特定するには、メソッド プロファイリングを使用する必要があります。

PS私は、ここにあなたのコードに小さなバグがあると思います:

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

あなたはおそらくこれを望んでいました:

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

PPS なぜNotification.FLAG_FOREGROUND_SERVICE旗を使うのですか?

于 2012-11-15T14:56:50.767 に答える
1

さて、私はついに問題が何であるかを理解しました。

このリンクにも興味があるかもしれません: 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をタイマーで再利用しているため、タイマーが実行されるたびに Notification オブジェクトを再作成するために CPU に負荷がかかることはありません。

したがって、上記のコードの変更により、私のコードは完全に機能するようになりました!

私を助けてくれてありがとう。

于 2012-11-18T13:39:15.987 に答える