サービスとは
サービスは、Androidでプログラムのバックグラウンド実行を実装するためのソリューションです。ユーザーの操作を必要とせず、長期間の実行を必要とするタスクを実行するのに非常に適しています。サービスの動作はユーザーインターフェースに依存しません。プログラムがバックグラウンドに切り替えられたり、ユーザーが別のアプリケーションを開いたりしても、サービスは正常に実行できます。
ただし、サービスは別のプロセスで実行されるのではなく、サービスが作成されたアプリケーションプロセスに依存することに注意してください。アプリケーションが強制終了されると、プロセスに依存するすべてのサービスも実行を停止します。
さらに、サービスの背景概念と混同しないでください。実際、サービスはスレッドを自動的に開始しません。すべてのコードはデフォルトでメインスレッドで実行されます。つまり、サービス内に子スレッドを手動で作成し、ここで特定のタスクを実行する必要があります。そうしないと、メインスレッドがブロックされる可能性があります。
Androidマルチスレッドプログラミング
Javaでのスレッドの作成方法と起動方法については、ここでは説明しません。Kotlinが提供するスレッドを開始する簡単な方法を紹介します。次のように記述されています。
thread{
//编写具体的逻辑
}
ここでのスレッドは、Kotlinに組み込まれているトップレベルの関数です。ラムダ式に特定のロジックを記述するだけで済みます。startメソッドを呼び出す必要もありません。スレッド関数は、すべてを内部で処理します。
Androidは、子スレッドでのUI操作を許可していません。ただし、子スレッドで時間のかかるタスクを実行してから、タスクの実行結果に応じて対応するUIコントロールを更新しなければならない場合があります。現時点では、Androidは、処理のために一連の非同期メッセージ処理メカニズム(ハンドラー)とAsyncTask(非同期メッセージメカニズムもその背後で使用され、メカニズムのカプセル化のセットが作成されます)を提供します。ハンドラーとAsyncTaskの基本的な使用法と原則は、関連資料に記載されていますが、ここでは説明しません。
サービスの基本的な使用法
- サービスの開始と停止
package com.example.myapplication
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
class MyService : Service() {
val TAG = "MyService"
override fun onBind(intent: Intent): IBinder {
return null
}
//service被创建的时候被调用
override fun onCreate() {
Log.e(TAG,"onCreate")
super.onCreate()
}
//service被销毁的时候被调用
override fun onDestroy() {
Log.e(TAG,"onDestroy")
super.onDestroy()
}
//每次service启动的时候调用,通常情况如果我们希望service一旦启动
// 就立刻执行某个动作,就可以将逻辑写在该方法中
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e(TAG,"onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
}
package com.example.myapplication
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_service.*
class ServiceActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_service)
startServiceBtn.setOnClickListener {
startService(Intent(this@ServiceActivity,MyService::class.java))
//启动service,如果多点几次的话,会发现只有onStartCommand方法被调用了,onCreate方法只在第一次的时候被调用
}
stopServiceBtn.setOnClickListener {
stopService(Intent(this@ServiceActivity,MyService::class.java))
//停止service,也有另外停止service的方式就是在service内部调用stopSelf()方法即可
}
}
}
AndroidManifest.xml
<!-- enabled表示是否启用这个service,exported表示是否将这个service暴露给外部其他程序访问 -->
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
上記はサービスの開始と停止の基本的な使用法ですが、Android 8.0システム以降、アプリケーションのバックグラウンド機能が大幅に削減されています。これで、アプリケーションがフォアグラウンドで表示されたままの場合にのみ、サービスは安定した動作を保証できます。アプリケーションがバックグラウンドに入ると、サービスはいつでもシステムによってリサイクルされる可能性があります。この変更の理由は、多くの悪意のあるアプリケーションがバックグラウンドで携帯電話のリソースを長期間占有し、携帯電話がますますスタックするのを防ぐためです。もちろん、本当に長時間バックグラウンドでいくつかのタスクを実行する必要がある場合は、フォアグラウンドサービスまたはワークマネージャーを使用できます。
- 活動とサービスのコミュニケーション
package com.example.myapplication
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
class MyService : Service() {
val TAG = "MyService"
private val mBinder = DownloadBinder()
inner class DownloadBinder:Binder(){
fun startDownload(){
Log.e(TAG,"startDownload")
}
fun getProgress():Int{
Log.e(TAG,"getProgress")
return 0
}
}
override fun onBind(intent: Intent): IBinder {
return mBinder
}
//service被创建的时候被调用
override fun onCreate() {
Log.e(TAG,"onCreate")
super.onCreate()
}
//service被销毁的时候被调用
override fun onDestroy() {
Log.e(TAG,"onDestroy")
super.onDestroy()
}
//每次service启动的时候调用,通常情况如果我们希望service一旦启动
// 就立刻执行某个动作,就可以将逻辑写在该方法中
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e(TAG,"onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
}
package com.example.myapplication
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.IBinder
import kotlinx.android.synthetic.main.activity_service.*
class ServiceActivity : AppCompatActivity() {
lateinit var downloadBinder: MyService.DownloadBinder//通过binder来实现activity指挥service干什么service就去干什么的功能
private val connection = object :ServiceConnection{
//在service的创建进程崩溃或者被杀掉的时候才会调用,这个方法不太常用
override fun onServiceDisconnected(name: ComponentName?) {
}
//在service与activity绑定的时候调用
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
downloadBinder = service as MyService.DownloadBinder
downloadBinder.startDownload()
downloadBinder.getProgress()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_service)
startServiceBtn.setOnClickListener {
startService(Intent(this@ServiceActivity,MyService::class.java))//启动service
}
stopServiceBtn.setOnClickListener {
stopService(Intent(this@ServiceActivity,MyService::class.java))
//停止service,也有另外停止service的方式就是在service内部调用stopSelf()方法即可
}
bindServiceBtn.setOnClickListener {
//Context.BIND_AUTO_CREATE:表示在activity和service进行绑定后自动创建service,这会使得service中onCreate方法被执行,但是onStartCommand方法不会执行
bindService(Intent(this@ServiceActivity,MyService::class.java),connection, Context.BIND_AUTO_CREATE)//绑定service
}
unbindServiceBtn.setOnClickListener {
unbindService(connection)//解绑service,回调service的onDestory方法
}
}
}
さらに、すべてのサービスはアプリケーション全体の範囲内でユニバーサルであることに注意してください。つまり、MyServiceはMainActivityにバインドできるだけでなく、他のアクティビティにもバインドでき、すべてのサービスはバインディングが完了しました。同じバインダーインスタンス(複数の異なるサービスが同じバインダーを操作できることを意味します)。
耐用年数
ContextのstartServiceメソッドがプロジェクト内の任意の場所で呼び出されると、対応するサービスが開始され、onStartCommand()メソッドがコールバックされます。サービスが以前に作成されたことがない場合、onCreateメソッドはonStartCommandメソッドの前に実行されます。サービスが開始された後、stopServiceメソッドまたはstopSelfメソッドが呼び出されるか、システムがリサイクルされるまで、サービスは実行され続けます。onStartCommandメソッドはstartServiceメソッドを1回呼び出さずに1回実行されますが、実際には各サービスのインスタンスは1つだけであることに注意してください。したがって、startServiceメソッドを何度呼び出しても、stopServiceまたはstopSelfメソッドを1回呼び出すだけで、サービスが停止します。
さらに、ContextのbindServiceメソッドを呼び出して、サービスへの永続的な接続を取得することもできます。そうすると、サービスのonBindメソッドがコールバックされます。同様に、サービスが以前に作成されたことがない場合、onCreateメソッドはonBindメソッドの前に実行されます。その後、呼び出し元はonBindメソッドで返されたIBinderオブジェクトのインスタンスを取得できるため、サービスと自由に通信できます。発信者とサービスの間の接続が切断されていない限り、サービスはシステムによってリサイクルされるまで実行され続けます。
startServiceメソッドを呼び出した後、stopServiceメソッドを再度呼び出します。このとき、サービスのonDestoryメソッドが実行され、サービスが破棄されたことを示します。同様に、bindServiceメソッドが呼び出されると、unbindServiceメソッドが呼び出されると、onDestoryメソッドも実行されます。ただし、サービスのstartServiceメソッドを呼び出してからbindserviceメソッドを呼び出す場合、この場合、サービスを破棄する場合は、stopserviceメソッドとunbindserviceメソッドを同時に呼び出す必要があり、ondestoryメソッドが実行されます。 。
サービスに関するその他のヒント
- フォアグラウンドサービスを使用するAndroid8.0
システム以降、サービスは、アプリケーションがフォアグラウンドで表示されたままの場合にのみ安定した動作を保証できます。アプリケーションがバックグラウンドに入ると、サービスはいつでもシステムによってリサイクルされる可能性があります。また、サービスを継続して実行する場合は、フォアグラウンドサービスの使用を検討できます。フロントエンドサービスと通常のサービスの最大の違いは、システムのステータスバーに常に実行中のアイコンが表示されることです。ステータスバーをプルダウンすると、より詳細な情報が表示されます。これは、通知の効果。
ステータスバーには常に実行中のアイコンがあるため、アプリケーションを別の形式でフォアグラウンドに表示したままにするのと同じです。したがって、システムはフォアグラウンドサービスをリサイクルする傾向がありません。また、ステータスバーをプルダウンすることで、実行中のアプリケーションを明確に把握できるため、悪意のあるアプリケーションがバックグラウンドで密かに携帯電話のリソースを長時間占有することはありません。ユーザーがプログラムを常に実行したくない場合は、アプリケーションを手動で強制終了して、サービスの実行を停止することもできます。
さらに、Android9.0システム以降、フォアグラウンドサービスを使用するには、androidManifest.xmlファイルで次の権限宣言を行う必要があります。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
フロントデスクサービスの基本的な使用法:クリックしてジャンプ
- IntentServiceを使用して、
時間のかかるビジネスロジックをサービスに記述したい場合は、スレッドを開く必要があります。Androidは、開発効率を向上させるためにIntentServiceクラスを提供しています。このクラスは、自動的に停止する非同期サービスを作成できます。
例は次のとおりです。
startIntentServiceBtn.setOnClickListener {
Log.e("ServiceActivity","Thread id is ${Thread.currentThread().name}")
val intent = Intent(this@ServiceActivity,MyIntentService::class.java)
startService(intent)
package com.example.myapplication
import android.app.IntentService
import android.content.Intent
import android.content.Context
import android.util.Log
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
Log.e("MyIntentService","Thread id is ${Thread.currentThread().name}")
}
override fun onDestroy() {//IntentService中onHandleIntent方法地逻辑执行完之后,会自动回调onDestory方法
super.onDestroy()
Log.e("MyIntentService","onDestory executed")
}
}