質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.78%

  • Java

    9661questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    4701questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

AndroidでService内で発行したTimerが端末スリープ状態で勝手に止まる

解決済

回答 1

投稿 2016/04/22 15:41

  • 評価
  • クリップ 0
  • VIEW 2,427

peishun

score 19

AndroidでServiceを用いて秒単位でカウントダウン処理を行い、Receiverを用いてその値を受け、Activity側でカウントダウン値を表示しています。
端末がスリープ状態でも動作するようにServiceを用いているのですが、端末がスリープするとなぜかカウントダウンが数秒〜数十秒後に止まってしまします。

Nortificationを作成してstartForegroundをしてシステムからキルされづらくしたり、WakeLockを取得してCPUを常に起動させたりといった対策はしたのですが解決しません。

以下にソースコードを記載します。どなたか解決策を提示していただけないでしょうか?

「Service」のソースコードは以下です

package jp.wings.nikkeiibp.napalerm.Process;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

import jp.wings.nikkeiibp.napalerm.Activity.CountDownActivity;
import jp.wings.nikkeiibp.napalerm.Common.IntentKeyWord;
import jp.wings.nikkeiibp.napalerm.R;


public class TimerService extends Service {

    //タイマー処理を行うオブジェクト
    private Timer mTimer = null;

    /** スリープ時のスクリーン及びCPUの制御を行うオブジェクト */
    private PowerManager.WakeLock mWakeLock;

    /** 設定した秒数 */
    private int mTimerSeconds;

    @Override
    public void onCreate() {
        super.onCreate();

        //CPUやスリープ画面の制御オブジェクト取得
        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Cowntdown_Start");

        //CPUを常にON状態にするのを開始(releaseするまで終了しない)
        mWakeLock.acquire();

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand ( Intent intent, int flags, int startId ) {

        //カウントダウンする時間を取得
        mTimerSeconds = intent.getIntExtra ( IntentKeyWord.SET_SECONDS, 0 );
        Log.i ( "TimerService getSecond", "" + mTimerSeconds );

        //通知を作成
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.nortification_title))
                .setContentText(getString(R.string.nortification_text))
                .setSmallIcon(R.mipmap.ic_launcher)
                .build();


        //通知削除不可にする
        notification.flags = Notification.FLAG_ONGOING_EVENT;

        //通知マネージャー取得
        NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

        //通知識別ID
        final int NUM = 1;

        //通知発行
        manager.notify(NUM, notification);

        //システムから殺されにくくする
        startForeground(NUM,notification);

        // タイマーの設定 1秒毎にループ
        mTimer = new Timer ();
        mTimer.schedule ( new TimerTask () {
            @Override
            public void run () {
                //カウントダウン
                mTimerSeconds--;
                //レシーバーに通知
                sendBroadCast();
            }
        }, 1000, 1000 );

        return START_STICKY;

    }

    @Override
    public void onDestroy () {
        mWakeLock.release();
        // タイマー停止
        if( mTimer != null ){
            mTimer.cancel();
            mTimer = null;
        }
        super.onDestroy ();
    }

    /**
     * レシーバーに値を渡す
     */
    protected void sendBroadCast() {

        Intent broadcastIntent = new Intent();
        broadcastIntent.putExtra(IntentKeyWord.SET_SECONDS, mTimerSeconds);
        Log.i ( "sendBroadCast setSecond", "" + mTimerSeconds );

        broadcastIntent.setAction("UPDATE_ACTION");
        getBaseContext().sendBroadcast(broadcastIntent);
    }
}

「Receiver」のソースコードは以下です

package jp.wings.nikkeiibp.napalerm.Process;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import jp.wings.nikkeiibp.napalerm.Common.IntentKeyWord;

public class TimerReceiver extends BroadcastReceiver{

    /** サービスから値を受け取ったときに動かす非同期処理 */
    public static Handler handler;

    @Override
    public void onReceive ( Context context, Intent intent ) {

        Bundle getbundle = intent.getExtras ();
        int seconds = getbundle.getInt ( IntentKeyWord.SET_SECONDS );
        Log.i ( "TimerReceiver getSecond", "" + seconds );

        if(handler !=null){

            Message msg = new Message();

            Bundle setbundle = new Bundle();

            setbundle.putInt ( IntentKeyWord.SET_SECONDS, seconds);
            Log.i ( "TimerReceiver setSecond", "" + seconds );

            msg.setData(setbundle);

            handler.sendMessage(msg);
        }
    }

    /**
     * 値受け取り時に実行する非同期処理の登録
     */
    public void registerHandler(Handler handler) {
        this.handler = handler;
    }
}

カウントダウンを表示するActivityのソースコードは以下

public class CountDownActivity extends Activity {

    /** サービスから値を受け取るレシーバー */
    private TimerReceiver mTimerReceiver;

    /** 暗黙的インテントの値を受け取る際のフィルター */
    private IntentFilter mIntentFilter;

    /** カウントダウン表示用テキスト */
    private TextView mCountText;

    /** 時間をカウントダウンするサービス */
    private Intent mService;

    @Override
    protected void onCreate ( Bundle savedInstanceState ) {
        super.onCreate ( savedInstanceState );
        setContentView ( R.layout.activity_count_down );

        mCountText = (TextView )findViewById( R.id.countDownText);

        //インテントから値を取得
        mService = new Intent(this , TimerService.class);
        int time = getIntent ().getIntExtra ( IntentKeyWord.SET_SECONDS, 0 );

        //時分秒を計算
        final int hour = time / 3600;
        final int minute = ( time % 3600 ) / 60;
        final int second = ( time % 3600 ) % 60;

        //初期秒数をテキストに表示
        setCountText(hour,minute,second);

        //0時間0分の場合+1秒(マイナスにカウントし始めるのを防ぐ)
        if(time == 0)
            time = 1;

        //サービスに秒数をセット
        mService.putExtra ( IntentKeyWord.SET_SECONDS, time );
        Log.i ( "service setSecond", "" + time );

        //タイマーサービス開始
        startService ( mService );

        //サービスのレシーバーをセット
        setReceiver ();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopService(mService);
    }

    /**
     * レシーバーをセット
     * レシーバーはサービスから値を受け取るもの
     */
    private void setReceiver(){
        mTimerReceiver = new TimerReceiver ();
        mIntentFilter = new IntentFilter ();
        mIntentFilter.addAction ( "UPDATE_ACTION" );
        registerReceiver ( mTimerReceiver, mIntentFilter );

        mTimerReceiver.registerHandler ( updateHandler );
    }

    /**
     * サービスから値を受け取った際の更新処理
     */
    private Handler updateHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            Bundle bundle = msg.getData ();
            int time =  bundle.getInt ( IntentKeyWord.SET_SECONDS );

            //カウントダウンが完了した
            if(time == 0){

                //サービス終了
                stopService(mService);

                //次のアクティビティへ
                goNotificaionAlert();

            }else{

                final int hour = time / 3600;
                final int minute = ( time % 3600 ) / 60;
                final int second = ( time % 3600 ) % 60;

                //カウントダウン表示更新
                setCountText(hour,minute,second);

            }
        }
    };


    /**
     * カウントダウンテキストをセットする
     * @param hour 時間
     * @param minute 分
     * @param second 秒
     */
    private void setCountText(int hour,int minute,int second){
        mCountText.setText ( String.format ( "%02d",hour ) +
                ":" + String.format ( "%02d",minute ) +
                ":" + String.format ( "%02d",second ));
    }


}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

https://groups.google.com/forum/#!topic/android-group-japan/OMGp8_9A5HE

上記に同じ現象で解決案も載ってます

投稿 2016/04/26 22:26

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    以下のような回答は評価を下げられます

    • 間違っている回答
    • 質問の回答になっていない投稿
    • 不快な投稿

    評価を下げる際はその理由をコメントに書き込んでください。

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.78%

関連した質問

同じタグがついた質問を見る

  • Java

    9661questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    4701questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。