RoadMovie

write down memos or something I found about tech things

Androidアプリを定期的に再起動してメモリをリセットする

C向けのサービスではあまりこういうことはしないと思いますが、B向けのサービスではこうした定期的にアプリを再起動するニーズがあるかもしれません。

アクティビティの再起動とアプリの再起動の二種類あるかと思うのですが、アクティビティ再起動はググればすぐ出てくるので、今回はアプリの再起動について書きます。これの利点としては、アプリ自体を一旦落として立ち上げ直すのでメモリがリセットされるということです。

さて、実際のコードはProcessPhoenixというライブラリを使えばいいだけなのでとても簡単です。 github.com

gradleで下記をインストール

implementation 'com.jakewharton:process-phoenix:2.0.0'

AndroidManifest.xmlに下記を追加

<!-- for Pheonix -->
<category android:name="android.intent.category.DEFAULT" />

あとは下記のコードをどこかに埋め込んだらリスタートできます。

ProcessPhoenix.triggerRebirth(context)


ついでに、こうした処理は定期的に行いたいと思うので、そのコードも紹介します。単純に数時間後とか数分おきにであればTimerを使ったりでできますが、私の要件ではcronで実行するような感じで深夜帯に一度再起動したかったので、android-jobというライブラリを使いました。 JobScheduler でもできるのですが、使い勝手がいいのと、彼らがブログで書いてるように学習コストが高いのでこちらを使っています。 github.com

こちらもgradleでインストール

implementation 'com.evernote:android-job:1.2.6'

JobCreatorを継承したクラスを作ります。ここでは MyJobCreator.kt とします。

import com.evernote.android.job.DailyJob
import com.evernote.android.job.JobCreator

 class MyJobCreator : JobCreator {
     override fun create(tag: String): DailyJob? {
        when (tag) {
            DailyJobScheduler.TAG -> return DailyJobScheduler()
            else -> return null
        }
    }
} 

Schedulerの実装体です。下記のような形で MyJobScheduler.kt を用意します。

import com.evernote.android.job.JobRequest
import com.evernote.android.job.DailyJob
import com.evernote.android.job.JobManager
import com.jakewharton.processphoenix.ProcessPhoenix
import java.util.concurrent.TimeUnit

 class DailyJobScheduler : DailyJob() {
     companion object {
        val TAG = "DailyJob"

         fun schedule() {
             // アプリ自体の再起動を行う関係で、Jobの実行が完了しないため、キューされた状態でアプリが起動されてしまいます。
             // そうすると、無限ループ的に再起動が繰り返されるので、キューに入れる前にすべてのキューをキャンセルして、
             // 実行されるジョブがひとつになることを担保しています。
            JobManager.instance().cancelAll()

             // https://github.com/evernote/android-job/wiki/FAQ
             // 午前3時に実行されます。(TAG, startTime, endTime)という引数のとり方をするので、
             // 3時~3時2秒まで実行可能にしています。ここに幅を持たせないと実行されないので注意。
            DailyJob.schedule(
                    JobRequest.Builder(TAG),
                    (TimeUnit.HOURS.toMillis(3)),
                    (TimeUnit.HOURS.toMillis(3) + TimeUnit.SECONDS.toMillis(2))
            )
        }
    }

     override fun onRunDailyJob(params: Params): DailyJobResult {
        ProcessPhoenix.triggerRebirth(context);  // 前述したアプリの再起動です。
        return DailyJobResult.SUCCESS;
    }
} 

そして、下記をApplicationを継承したクラスのonCreateなどで呼んでおきます。

JobManager.create(this).addJobCreator(MyJobCreator())
DailyJobScheduler.schedule()

これで午前3時に一度メモリリセットのためにアプリが自動で再起動されるようになりました。 いい感じですね。