タイトルのようなことがしたくて、色々と検証。
同時にライフサイクルも確認した。
メインスレッドが落ちたか、で確認したかったが
アクティビティが終了したあとも、プロセスが終了せずメインスレッドも消えなかったため
タスクの状態をサービスで確認することとした。
MainActivity.kt-----------------
package com.example.learningandroid
import android.content.ContentValues.TAG
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.learningandroid.ui.theme.LearningAndroidTheme
import android.os.Process
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreateは開始一回しか出ないはず")
// メインアクティビティのスレッドを取得
val mainThread = Thread.currentThread()
// これだとmainがとれるか
Log.d(TAG, "色々出してみる、まず名前:" + mainThread.name)
// メインアクティビティのスレッドのIDを取得
//val mainThreadId = Thread.currentThread().id
//Log.d(TAG, "ここでもスレッドIDみておくか:" + mainThreadId)
// プロセスID=メインスレッドのIDのようなのでなのでPID撮ってみる
val myPid = Process.myPid()
Log.d(TAG, "myPidはどうか:" + myPid)
// サービス起動
val serviceIntent = Intent(this, MainService::class.java)
serviceIntent.putExtra("mainThreadId", myPid)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
setContent {
LearningAndroidTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
}
// ライフサイクルを色々試す
override fun onStart() {
super.onStart()
Log.d(TAG, "onStartしたとき")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResumeのタイミング")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPauseのタイミング、隠れた時?")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStopのタイミング、これも隠れた時?")
}
override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestartのタイミング、おそらく復帰した時")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroyのタイミング、今回はめられたやつ")
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
LearningAndroidTheme {
Greeting("Android")
}
}
MainService.kt-----------------
package com.example.learningandroid
import android.app.ActivityManager
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.os.Looper
import android.util.Log
import androidx.core.app.NotificationCompat
import java.util.Timer
import java.util.TimerTask
import kotlin.concurrent.thread
class MainService : Service() {
companion object {
private const val NOTIFICATION_CHANNEL_ID = "MainChannel"
private const val NOTIFICATION_ID = 1
}
private val tag = this::class.simpleName
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 通知チャンネルの作成
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null) {
val channel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
"バックグラウンド処理",
NotificationManager.IMPORTANCE_HIGH).apply {
description = "バックグラウンド処理の通知です"
}
notificationManager.createNotificationChannel(channel)
}
}
// 通知の作成
val notification = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setContentTitle("バックグラウンド処理")
.setContentText("処理中です")
.setSmallIcon(R.mipmap.ic_launcher)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
// // フォアグラウンドサービスにする
// startForeground(NOTIFICATION_ID, notification)
var count = 0
// 改造、カウントアップしてたところ
// ここでメインスレッドが
thread {
while (true) {
//Log.d(tag, "count=$count")
count++
Thread.sleep(1000)
Log.d(tag, "これでタスクそのものが取れる?")
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val runningTasks = activityManager.getRunningTasks(1)
if (runningTasks.isNotEmpty()) {
val topActivity = runningTasks[0].topActivity
// topActivityには現在の最上位アクティビティの情報が含まれます
Log.d(tag, "動いてる?")
}else{
Log.d(tag, "止まった・・・")
}
}
}
// メインスレッドの状態を定期的に監視するタイマーを開始
// thread {
// val timer = Timer()
// timer?.scheduleAtFixedRate(object : TimerTask() {
// override fun run() {
// val mainThread = Looper.getMainLooper().thread
//
// if (mainThread.isAlive) {
// // メインスレッドが実行中の場合
// Log.d(tag, "こっちを別スレッドにしてみた、メインが生きてるよ")
// } else {
// // メインスレッドが終了している場合
// Log.d(tag, "こっちを別スレッドにしてみた、メインが落ちた")
// }
// }
// }, 0, 1000) // 1秒ごとに確認
// }
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
throw UnsupportedOperationException()
}
override fun onDestroy() {
Log.d(tag, "onDestroy:")
super.onDestroy()
}
}
AndroidManifest.xml-----------------
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LearningAndroid"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.LearningAndroid">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MainService" />
</application>