如何使用Service(kotlin)

如何使用Service(kotlin)

-

為什麼要使用Service?

  • 將元件的生命週期跟 Thread 的生命週期分開(避免前述 Thread 參考到元件,在 Thread 結束前無法釋放物件導致Memory leak)
  • 當一個 Process 內只剩下 Thread 在執行,避免 Process 被系統意外回收,導致 Thread 被提前結束。
  • 跨行程。

Service分成兩種: startService 和 bindService。

  • startService: 由第一個元件啟動,由第一個元件結束,這個是最常見的,也是最簡單的啟動方式。

一開始先宣告一個 Service 的類別。

class ServiceDemo : Service() {  
	override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {  
		return super.onStartCommand(intent, flags, startId)  
	}  

	override fun onBind(p0: Intent?): IBinder? {  
		return null  
	}  
}

由於是啟動 Service,因此 onBind 會是 return null,由於 Service 是運作在 UI Thread 上面,因此,你必須將長任務開個 Thread 並且執行在 onStartCommand 方法內。

接著Actvitiy對此類別進行啟動。

val intent = Intent(this, ServiceDemo.class)
startService(intent)

這樣就可以啟動一個 Service 了。

有時候在系統記憶體吃緊的時候,會將系統某些 Service 收起來,這時候有幾個參數可以讓系統替你重新啟動Service。

  • START_STICKY : Service 被殺掉,系統會重啟,但是 Intent 會是 null。
  • START_NOT_STICKY : Service 被系統殺掉,不會重啟。
  • START_REDELIVER_INTENT : Service 被系統殺掉,重啟且 Intent 會重傳。
    透過以上的參數,放在 onStartCommand 的 return 參數就可以使用重啟的功能了。

bindService

  • 由第一個元件進行連繫 (bind),此時 Service 就會啟動,接著後面可以多個元件進行 bind,而當所有的元件都結束連繫 (unbind),則 Service 會進行銷毀。
class ServiceDemo : Service() {  
	private val binder = MyBinder()  

	override fun onBind(p0: Intent?): IBinder? {  
		return binder  
	}  

	override fun onUnbind(intent: Intent?): Boolean {  
		return super.onUnbind(intent)  
	}  
	
	fun getServiceName():String{  
	    return ServiceDemo::class.java.name  
	}
	
	inner class MyBinder : Binder() {  
		val service: ServiceDemo  
			get() = this@ServiceDemo  
	}  
}

以上程式碼可以看到 Service 的宣告,此時你可以宣告一個 Binder,透過 Binder 來取得整個 Service 的實體,因此,你可以透過這個實體來引用 Service 上任何一個公開的方法。

private val mLoaclServiceConnection = LoaclServiceConnection()
class MainActivity : AppCompatActivity() {  
  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)
		bindService(Intent(this, ServiceDemo::class.java), mLoaclServiceConnection, 	Context.BIND_AUTO_CREATE)
    }
}
class LoaclServiceConnection : ServiceConnection {  
	override fun onServiceConnected(name: ComponentName, service: IBinder) {  
		//透過Binder調用Service內的方法  
		val name = (service as ServiceDemo).getServiceName()  
	}  

	override fun onServiceDisconnected(name: ComponentName) {  
		//service 物件設為null  
	}  
}

在這邊連繫的 Service 必須傳入一個 ServiceConnection 物件,而當連繫成功以後,就會呼叫ServiceConnection 的 onStartConnection 方法,將 Service 的 Binder 回傳回來,透過轉型為 Service 本身的實體,就可以操作 Service 上的任意方法。

這樣就是一個最簡單的 Service 雙向溝通。