android學習筆記 - service(kotlin實現)

#service從入門到放棄

微信公衆號:沒有
如果你覺得此文章對你有幫助,歡迎點贊

###service簡介
service和activity 、contentProvider、BroadcastReceiver並稱爲Android四大組件,其地位不言而喻,在使用中也確實舉足輕重。service的直接翻譯爲服務,它是一種在後臺執行長時間運行才最而沒有UI的應用組件。service可以理解爲沒有界面的activity,非常適合用於執行不需要交互界面且長期後臺運行的任務。service不能運行在獨立的進程中,需要依賴創建服務時所在的應用程序進程。服務器不會自動開啓工作線程,它和activity一樣,創建之後會創建一個主線程,工作線程需要我們手動創建服務可由其他應用組件啓動(如Activity),啓動方式後邊詳細講。
service基本上分爲兩種狀態:

啓動狀態:

如果一個service是通過startService() 方式啓動的,服務當前的狀態即爲“啓動”狀態。一旦啓動,服務即可在後臺長期運行,急事啓動該服務的組件已經被銷燬,也無任何影響,因爲服務此時不依賴任何組件,是獨立運行的,除非手動調用停止或者強行停止運行應用才能停止服務,已啓動的服務通常是執行單一操作,而且不會把結果返回給調用方。

綁定狀態:

如果一個service是通過bindService() 方式啓動的,則該服務是“綁定”狀態。綁定的服務提供了 客戶端-服務端的接口,允許組件與服務器進行交互、發送請求和獲取數據,並且可以利用IPC(進程通信機制)進行跨進程執行這些操作。此服務生命週期與綁定該服務的組件一致,組件銷燬後綁定的服務也會停止運行。

service創建及使用(啓動狀態)

  • 1.定義一個service:

步驟如下:

  • 創建一個類集成自android.app.Service,實現抽象方法onBind(),重寫onCreate()、onStart()()、onCommand()、onDestry();

注意
該方法已被棄用

  • 在AndroidManifest.xml清單文件中註冊該service;
具體實現:(使用kotlin語言實現)
  1. service代碼:
class BookService : Service() {

    val TAG = "BookService"
    override fun onBind(intent: Intent): IBinder? {
        LogUtils.i(TAG,"onBind")
        return null
    }

    override fun onCreate() {
        super.onCreate()
        LogUtils.i(TAG,"onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        LogUtils.i(TAG,"onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        LogUtils.i(TAG,"onDestroy")
    }
}
  1. AndroidManifest.xml 文件中註冊:
 <service android:name=".services.BookService"/>
  1. activity中的代碼:
private val TAG = "MainActivity"
val RECEIVE_MESSAGE_CODE : Int  = 0x0002

//客戶端的消息處理
class ClientHndler : Handler(){
    override fun handleMessage(msg: Message?) {
        super.handleMessage(msg)
        LogUtils.i(TAG,"clientHndler")
        when (msg?.what) {
            RECEIVE_MESSAGE_CODE -> {
                LogUtils.i(TAG,"這是來自服務端的問候:" + msg.obj)
            }
            else -> {
                LogUtils.i(TAG,"未接收到服務端的問候!!!")
            }
        }
    }
}

//初始化客戶端的messenger
val clientMessenger = Messenger(ClientHndler())

class MainActivity : AppCompatActivity(),ServiceConnection{

    override fun onServiceDisconnected(p0: ComponentName?) {
        //TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        LogUtils.i(TAG,"onServiceDisconnected")
    }

    private lateinit var movieService: MovieService

    override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
        //TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        LogUtils.i(TAG,"onServiceConnected")
        var movieBinder = p1 as MovieService.MovieBinder
        movieService = movieBinder.getMovieService()
    }



    class Conn : ServiceConnection{
        val TAG = "Conn"
        override fun onServiceDisconnected(p0: ComponentName?) {
            // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            LogUtils.i(TAG,"onServiceDisconnected")
        }

        lateinit var serviceMessenger: Messenger

        override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
            // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            LogUtils.i(TAG,"onServiceConnected")
            serviceMessenger = Messenger(p1)
        }

    }


    val conn = Conn()

    private var bookbinders = Intent()
    private var movieBinders = Intent()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        LogUtils.i(TAG,"onCreate")
        //直接啓動service
        btn_start.setOnClickListener {
            bookbinders.setClass(this,BookService().javaClass)
            startService(bookbinders)
        }
        //停止service
        btn_stop.setOnClickListener {
            stopService(bookbinders)
        }

        //綁定service
        btn_bind.setOnClickListener {
            movieBinders.setClass(this,MovieService::class.java)
            bindService(movieBinders,this,Service.BIND_AUTO_CREATE)
        }
        //解除綁定
        btn_unbind.setOnClickListener {
            unbindService(this)
        }
        //獲取數據
        btn_getdata.setOnClickListener {
            val count = movieService.movieName
            println("從service獲取的count===$count")
        }
        //msg  bind
        btn_msg_bind.setOnClickListener {
            var  intent = Intent()
            intent.setClass(this@MainActivity,MusicService::class.java)
            bindService(intent,conn,Service.BIND_AUTO_CREATE)
        }
        //給service發送消息
        btn_send_msg.setOnClickListener {
            val message = Message.obtain(null, SEND_MESSAGE_CODE, 0, 0)
            message.obj = "來自客戶端的問候!!!"
            message.replyTo = clientMessenger
            conn.serviceMessenger.send(message)
        }
        //取消綁定
        btn_msg_unbind.setOnClickListener {
            unbindService(conn)
        }
    }


    override fun onStart() {
        super.onStart()
        LogUtils.i(TAG,"onStart")
    }

    override fun onRestart() {
        super.onRestart()
        LogUtils.i(TAG,"onRestart")
    }

    override fun onResume() {
        super.onResume()
        LogUtils.i(TAG,"onResume")
    }
    override fun onPause() {
        super.onPause()
        LogUtils.i(TAG,"onPause")
    }

    override fun onDestroy() {
        super.onDestroy()
        LogUtils.i(TAG,"onDestroy")
    }


}

  1. 界面佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:text="@string/main_start"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.16"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btn_bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:text="@string/main_bind"
        app:layout_constraintBottom_toTopOf="@+id/btn_start"
        app:layout_constraintEnd_toEndOf="@+id/btn_start"
        app:layout_constraintStart_toStartOf="@+id/btn_start" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:text="@string/main_stop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.053"
        app:layout_constraintStart_toEndOf="@+id/btn_start" />

    <Button
        android:id="@+id/btn_unbind"
        android:layout_width="103dp"
        android:layout_height="47dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:text="@string/main_unbind"
        app:layout_constraintBottom_toTopOf="@+id/btn_stop"
        app:layout_constraintEnd_toStartOf="@+id/btn_getdata"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="@+id/btn_stop" />

    <Button
        android:id="@+id/btn_getdata"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:text="獲取數據"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn_stop"
        app:layout_constraintTop_toTopOf="@+id/btn_bind"
        app:layout_constraintVertical_bias="0.0" />

    <Button
        android:id="@+id/btn_msg_bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="112dp"
        android:text="綁定service(msg)"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:layout_editor_absoluteX="16dp" />

    <Button
        android:id="@+id/btn_msg_unbind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="取消綁定service(msg)"
        app:layout_constraintBottom_toTopOf="@+id/btn_msg_bind"
        tools:layout_editor_absoluteX="16dp" />

    <Button
        android:id="@+id/btn_send_msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:text="發消息給service"
        app:layout_constraintBottom_toTopOf="@+id/btn_unbind"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.46"
        app:layout_constraintStart_toEndOf="@+id/btn_msg_bind" />
</android.support.constraint.ConstraintLayout>

接下來看一下service啓動的過程:
點擊“啓動service”按鈕:查看logcat:

09-25 14:03:09.307 16466-16466/com.xyd.servicedemo I/BookService:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.BookService.onCreate(BookService.kt:18)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = BookService
    │ args[1] = onCreate
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
     
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.BookService.onStartCommand(BookService.kt:22)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = BookService
    │ args[1] = onStartCommand
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

從log可以看到,當使用startService()方式啓動service時,service調用了onCreate 和 onStartCommand方法,service就被啓動了。startservice的啓動過程可以看這篇文章
然後我們再停止該service:

09-25 14:09:14.074 16466-16466/com.xyd.servicedemo I/BookService:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.BookService.onDestroy(BookService.kt:28)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = BookService
    │ args[1] = onDestroy
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

停止service調用的是:stopService(),當服務停止時,調用了service的onDestroy方法。

通過上邊的例子可以看到通過startservice啓動的service的生命週期,可以通過相應的方法管理service,並且啓動的service不依賴與啓動它的Activity,如果當前activity銷燬,service也不會被銷燬,還是會在後臺運行,感興趣的朋友可以試試。

service創建及使用(綁定狀態)

創建同上:具體步驟不寫了,直接上代碼吧!
service代碼:

class MovieService : Service(){

    private val TAG = "MovieService"
    private var movieBinder = MovieService.MovieBinder(this@MovieService)

    private var isRun: Boolean = true


    var count: Int = 0
    var movieName: String = ""

    private lateinit var myThread: Thread

    override fun onCreate() {
        super.onCreate()
        LogUtils.i(TAG,"onBind")
        myThread =  object : Thread() {
            override fun run() {
                println("running from Thread: ${Thread.currentThread()}")
                while (isRun){
                    try {
                        Thread.sleep(2000)
                    } catch (e: Exception) {
                    }
                    count++
                    movieName = "復仇者聯盟$count"
                    println(movieName)
                }
            }
        }
        myThread.start()

    }
    override fun onBind(p0: Intent?): IBinder {
        // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        LogUtils.i(TAG,"onBind")
        return movieBinder
    }


    class MovieBinder(private val movieService: MovieService) : Binder(){
        val TAG = "MovieBinder"
        fun getMovieService() : MovieService{
            LogUtils.i(TAG,"getMovieService")
            return movieService
        }
    }

    override fun unbindService(conn: ServiceConnection?) {
        super.unbindService(conn)
        LogUtils.i(TAG,"unbindService")
    }


    override fun onDestroy() {
        super.onDestroy()
        isRun = false
        LogUtils.i(TAG,"onDestroy")
    }


}

activity代碼已在上個例子中貼出,請查看。需要注意的是,與startservice方式不同的是,bindservice時需要創建一個ServiceConnection的實例,在bindservice時傳遞給service,該實例的作用是客戶端與服務端通訊的媒介,具體可看一下這篇文章

運行:直接點擊“綁定service”按鈕,查看log:

    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.MovieService.onBind(MovieService.kt:45)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = MovieService
    │ args[1] = onBind
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-25 14:32:52.109 16821-18011/com.xyd.servicedemo I/System.out: running from Thread: Thread[Thread-4,5,main]
09-25 14:32:52.109 16821-16821/com.xyd.servicedemo I/MainActivity:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.MainActivity.onServiceConnected(MainActivity.kt:52)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = MainActivity
    │ args[1] = onServiceConnected
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-25 14:32:52.110 16821-16821/com.xyd.servicedemo I/MovieService:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.MovieService$MovieBinder.getMovieService(MovieService.kt:53)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = MovieBinder
    │ args[1] = getMovieService
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

通過bindservice後,服務啓動,並且在客戶端的ServiceConnection中回掉了onServiceConnected()方法,表示客戶端已與服務端建立了連接,此時客戶端是可以和服務端單向通訊的。如果是綁定狀態的service,是依賴於啓動它的activity的,當該activity銷燬後,綁定的service也會被銷燬。

接下來看一下客戶端與服務端的通訊:
實例:客戶端的代碼一貼出,下邊看一下服務端的代碼

/**
 * Created by zejian
 * Time 2016/10/3.
 * Description:Messenger服務端簡單實例,服務端進程
 */

//此變量定義在類外部就可以被全包訪問
val  SEND_MESSAGE_CODE : Int = 0x0001


//服務端的消息處理
class InComingHandler : Handler(){

    override fun handleMessage(msg: Message?) {
        super.handleMessage(msg)
        if (msg != null) {
            when (msg.what) {
                SEND_MESSAGE_CODE -> {
                    LogUtils.i("接受到客戶端消息:" + msg.obj)
                    //接受完客戶端的消息後需要返回給客戶端消息
                    //通過msg.replyTo 方法 獲取客戶端的messenger
                    val clientMessenger = msg.replyTo
                    //獲取到messenger之後,在通過客戶端的messenger給客戶端發送消息
                    val msg = Message.obtain()
                    msg.what = RECEIVE_MESSAGE_CODE
                    msg.obj = "hello client!!!"
                    Thread.sleep(3000)
                    clientMessenger.send(msg)
                }
                else -> {
                    LogUtils.i("未接受到客戶端消息")
                }
            }
        }

    }
}
private val mMessenger = Messenger(InComingHandler())

class MusicService : Service(){


    override fun onBind(p0: Intent?): IBinder? {
        // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        return mMessenger.binder
    }

}

主要的處理邏輯已在代碼中標明,請自行查看。

下面解決幾個問題:

  • 1、Service的start和bind狀態有什麼區別?

首先第一個問題:

  • Service的start和bind狀態的區別:首先是啓動方式不同,start是直接啓動,而bind是依賴於組件啓動的,其次是啓動的生命週期不同,start啓動時執行的是onCreate
    、onStartCommand的方法,而bind啓動執行的是onBind方法。最後是start方式啓動的service可以獨立於組件運行,組件銷燬之後,service不會停止運行,而bind方式啓動的service則是依附於組件,組件銷燬後,service會被強制停止運行。
  • 2、同一個Service,先startService,然後再bindService,如何把它停止掉?
    這個問題可以通過例子來看:新建一個service,並且在清單文件中註冊:
class StartAndBindService : Service() {

    val TAG = "StartAndBindService"
    override fun onBind(intent: Intent): IBinder? {
        LogUtils.i(TAG,"onBind")
        return null
    }

    override fun onCreate() {
        super.onCreate()
        LogUtils.i(TAG,"onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        LogUtils.i(TAG,"onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        LogUtils.i(TAG,"onDestroy")
    }
}

然後在activity中新建兩個按鈕並設置點擊事件,一個按鈕是start,一個按鈕是bind,運行之後,先點擊start,然後點擊bind,會出現以下結果:

09-26 12:59:55.249 4898-4898/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onCreate(StartAndBindService.kt:19)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onCreate
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 12:59:55.255 4898-4898/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onStartCommand(StartAndBindService.kt:23)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onStartCommand
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 12:59:57.826 4898-4898/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onBind(StartAndBindService.kt:13)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onBind
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────

可以看出先啓動,然後在bind,兩種啓動都會執行,但是如果已這種方式啓動之後,調用stopservice,service不會被停止,而調用unbindservice後service纔會被停止,由此可見,service由start方式啓動,然後在調用bind之後,是先啓動,然後在和組件綁定,其實只是一個service,因爲onstart方法已被啓用,所以看不出來,其實在調用onbind的時候,不會再走onstart方法。
  • 3、你有注意到Service的onStartCommand方法的返回值嗎?不同返回值有什麼區別?
    這個問題可以看這篇文章,這個反之沒有研究過

  • 4、Service的生命週期方法onCreate、onStart、onBind等運行在哪個線程?

這個可以在service中打log查看,咱們來看看:

09-26 13:34:43.271 5937-5937/com.xyd.servicedemo I/StartAndBindService:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.StartAndBindService.onCreate(StartAndBindService.kt:25)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = StartAndBindService
    │ args[1] = onCreate運行在主線程
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 13:34:43.273 5937-5937/com.xyd.servicedemo I/StartAndBindService:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.StartAndBindService.onStartCommand(StartAndBindService.kt:41)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = StartAndBindService
    │ args[1] = onStartCommand運行在主線程
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
     
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.StartAndBindService.onStart(StartAndBindService.kt:34)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = StartAndBindService
    │ args[1] = onStart運行在主線程
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 13:34:47.690 5937-5937/com.xyd.servicedemo I/StartAndBindService:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xyd.servicedemo.services.StartAndBindService.onDestroy(StartAndBindService.kt:51)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ args[0] = StartAndBindService
    │ args[1] = onDestroy運行在主線程
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

具體使用的判斷爲:Looper.getMainLooper() == Looper.myLooper()

demo地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章