Simple use of Service in Android

Table of contents

Create a Service

Communication between Activity and Service

Bind Activity and Service

Use the foreground Service 

Use IntentService


Create a Service

Each Service needs to be registered in ActivityManifest.xml, and generally it will be registered automatically.

Register service:

<service
        android:name=".MyService"
        android:enabled="true"
        android:exported="true">
</service>

Create service: 

class MyService : Service() {

   override fun onBind(intent: Intent): IBinder {
       
    }

    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "onCreate executed")
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d("MyService", "onStartCommand executed")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService", "onDestroy executed")
    }

}

 Under normal circumstances, we will execute some actions immediately after starting the service. Those actions can be written in  onStartCommand , not in onCreate. OnCreate will only be called when the service is created for the first time. onDestroy() is responsible for releasing resources when the service ends. Such a service is created. The next step is to enable and stop the service. First, define two buttons in activity_main.xml to start and stop the service. Then set the listening event in the activity:

        startServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            startService(intent) // 启动Service
        }
        stopServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            stopService(intent) // 停止Service
        }

This completes the basic use of the service.

Communication between Activity and Service

Bind Activity and Service

To realize the communication between Activity and Service, the onBind method must be used. The onBind method enhances the connection between service and activity. It is the way of communication between service and activity, so that activity can decide when to use service and view the progress of service. . A DownloadBinder class inherited from Binder is defined here, and then two methods are defined inside the class for simulating download operations (in fact, neither of these two methods is specifically implemented). Finally, use the onBind method to pass the instance mBinder of this class to the Activity.

class MyService : Service() {

   private val mBinder = DownloadBinder()

    class DownloadBinder : Binder() {

        fun startDownload() {
            Log.d("MyService", "startDownload executed")
        }

        fun getProgress(): Int {
            Log.d("MyService", "getProgress executed")
            return 0
        }

    }

    override fun onBind(intent: Intent): IBinder {
        return mBinder
    }

    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "onCreate executed")
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d("MyService", "onStartCommand executed")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService", "onDestroy executed")
    }

}

Then bind the service in the Activity, and define two buttons in activity_main.xml for binding and unbinding the service. First, we implement the anonymous class implementation of ServiceConnect, and rewrite the onServiceConnected method and onServiceDisconnected method. The onServiceConnected method is called when the Activity and service are successfully bound, and the onServiceDisconnected method is called when the service crashes or the process is killed. The bindService method is used during binding, and the parameters passed in are Intent object , ServiceConnection instance , and flag (here Context.BIND_AUTO_CREATE means that the binding is successful and the service is automatically created. At this time, onCreate will be executed, but onStartCommand will not be executed). Note that when the service is unbound, the onDestroy method in the service will be executed, but if the startService method has been executed before, then the stopService and unbindService methods need to be called at the same time to destroy the service.

class MainActivity : AppCompatActivity() {

    lateinit var downloadBinder: MyService.DownloadBinder

    private val connection = object : ServiceConnection {

        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            downloadBinder = service as MyService.DownloadBinder
            downloadBinder.startDownload()
            downloadBinder.getProgress()
        }

        override fun onServiceDisconnected(name: ComponentName) {
            Log.d("MyService", "onServiceDisconnected")
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        startServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            startService(intent) // 启动Service
        }
        stopServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            stopService(intent) // 停止Service
        }
        bindServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service
        }
        unbindServiceBtn.setOnClickListener {
            unbindService(connection) // 解绑Service
        }
    }

}

Use the foreground Service 

The background service cannot guarantee stable operation, so we can use the foreground service to transform the service, as follows:

class MyService : Service() {

    private val mBinder = DownloadBinder()

    class DownloadBinder : Binder() {

        fun startDownload() {
            Log.d("MyService", "startDownload executed")
        }

        fun getProgress(): Int {
            Log.d("MyService", "getProgress executed")
            return 0
        }

    }

    override fun onBind(intent: Intent): IBinder {
        return mBinder
    }

    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "onCreate executed")
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel("my_service", "前台Service通知", NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }
        val intent = Intent(this, MainActivity::class.java)
        val pi = PendingIntent.getActivity(this, 0, intent, 0)
        val notification = NotificationCompat.Builder(this, "my_service")
            .setContentTitle("This is content title")
            .setContentText("This is content text")
            .setSmallIcon(R.drawable.small_icon)
            .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon))
            .setContentIntent(pi)
            .build()
        startForeground(1, notification)
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d("MyService", "onStartCommand executed")
        thread {
            // 处理具体的逻辑
            stopSelf()
        }
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService", "onDestroy executed")
    }

}

Modify the onCreate method and onStartCommand method, and change from the background service to the foreground service is actually to write the message notification into the service, because the foreground service also needs to declare the permissions , so the AndroidManifest.xml file must be modified as follows:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.servicetest">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
...
</manifest>

 The reason for modifying the onStartCommand method is that the service runs in the main thread, so time-consuming operations in the service will cause ANR (application not responding) problems. Therefore, we need to open sub-threads in the method to handle time-consuming operations, and use stopSelf() to stop the service.

Use IntentService

Because it is too cumbersome to frequently open threads when the service handles time-consuming operations, IntentService is launched. The method of use is as follows:

class MyIntentService : IntentService("MyIntentService") {

    override fun onHandleIntent(intent: Intent?) {
        // 打印当前线程的id
        Log.d("MyIntentService", "Thread id is ${Thread.currentThread().name}")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyIntentService", "onDestroy executed")
    }

}

Don't forget to register service in AndroidManifest.xml

<service
            android:name=".MyIntentService"
            android:enabled="true"
            android:exported="true"/>

 Time-consuming operations can be performed in onHandleIntent, which runs in sub-threads, and the specific usage in Activity is as follows:

Define a button here to start the IntentService

startIntentServiceBtn.setOnClickListener {
            // 打印主线程的id
            Log.d("MainActivity", "Thread id is ${Thread.currentThread().name}")
            val intent = Intent(this, MyIntentService::class.java)
            startService(intent)
        }

 

Guess you like

Origin blog.csdn.net/liny70858/article/details/127403347