Android 第二十七章 Service

一、继承

java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.app.Service

二、简介

service:Android四大组件之一,处理不需要在界面上显示的工作

三、配置

需要在AndroidManifest.xml中,注册service基本信息

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <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.ServiceDemo"
        tools:targetApi="31">

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

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

四、公共方法

  1. getApplication() 返回当前服务应用程序
  2. getForegroundServiceType() 如果服务已通过调用成为前台服务 startForeground(int, android.app.Notification) 或 startForeground(int, android.app.Notification, int), getForegroundServiceType() 返回当前前台服务类型
  3. onBind(intent: Intent) 将通信信道返回到服务。如果不绑定到服务,设置为null
  4. onCreate() 首次创建服务时由系统调用,如果服务存在,则不在调用
  5. onStartCommand(intent: Intent, flags: Int, startId: Int) 每次启动服务时,系统都会调用该方法
  6. onUnbind(intent: Intent) 断开与服务链接时调用
  7. onDestroy() 服务销毁时调用
  8. onConfigurationChanged(newConfig: Configuration) 当设备配置更改时由系统调用,而 组件正在运行
  9. onLowMemory() 当整个系统内存不足时,将调用此值,并且 主动运行的进程应减少其内存使用量。
  10. onRebind(Intent intent) 当新客户端连接到该服务时调用,此前该服务在其onUnbind中被通知所有客户端都已断开连接。只有当onUnbind的实现被重写以返回true时,才会调用此函数。
  11. onTaskRemoved(Intent rootIntent) 如果服务当前正在运行,并且用户删除了来自服务应用程序的任务,则调用此操作。如果您已设置ServiceInfo.FLAG_STOP_WITH_TASK,则不会收到此回调;相反,该服务将被简单地停止。
  12. onTimeout(int startId) 超时调用
  13. onTrimMemory(int level) 当操作系统确定它是好的时调用 进程从其进程中修剪不需要的内存的时间。
  14. startForeground(int id, Notification notification) 如果您的服务已启动(运行 Context#startService(Intent)),然后 还要使此服务在前台运行,提供正在进行的 处于此状态时向用户显示的通知。
  15. stopForeground(int notificationBehavior) 从前台状态删除此服务,允许在以下情况下将其终止 需要更多的内存。
  16. stopSelf() 停止该服务

五、生命周期

1.不绑定服务,通过startService启动服务
  1. onCreate() 创建Service,首次创建调用
  2. onStartCommand() 服务开始运行
  3. onDestroy() 销毁服务
2.绑定服务,通过startService启动服务
  1. onCreate() 创建Service,首次创建调用
  2. onBind() 绑定服务,服务开始运行
  3. onUnbind() 解除绑定
  4. onDestroy() 销毁服务

六、实例

1.不绑定服务
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <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.ServiceDemo"
        tools:targetApi="31">

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

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>
class TestService : Service() {

    val TAG = "TestService"

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

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

    override fun onBind(intent: Intent): IBinder? {
        Log.i(TAG, "onBind")
        return null
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.i(TAG, "onUnbind")
        return super.onUnbind(intent)
    }

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

}
class MainActivity : AppCompatActivity() {

    private lateinit var btn_startService: Button
    private lateinit var btn_stopService: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initView()
        initData()
        initClick()
    }

    private fun initView() {
        btn_startService = findViewById(R.id.btn_startService)
        btn_stopService = findViewById(R.id.btn_stopService)
    }

    private fun initData() {

    }

    private fun initClick() {
        btn_startService.setOnClickListener {
            startService(Intent(this, TestService::class.java))
        }
        btn_stopService.setOnClickListener {
            stopService(Intent(this, TestService::class.java))
        }
    }

}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_startService"
        android:layout_width="300dp"
        android:layout_height="100dp"
        android:text="启动服务"
        android:textSize="40sp" />

    <Button
        android:id="@+id/btn_stopService"
        android:layout_width="300dp"
        android:layout_height="100dp"
        android:layout_marginTop="30dp"
        android:text="停止服务"
        android:textSize="40sp" />

</LinearLayout>
2.绑定服务

class TestService : Service() {

    val TAG = "TestService"

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

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

    override fun onBind(intent: Intent): IBinder? {
        Log.i(TAG, "onBind")
        return TestBinder()
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.i(TAG, "onUnbind")
        return true
    }

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

    class TestBinder : Binder() {
        fun dragon(mContext: Context) {
            Toast.makeText(mContext, "呜呼~", Toast.LENGTH_LONG).show()
        }
    }

}
class TestServiceConnection : ServiceConnection {

    val TAG = "TestServiceConnection"
    lateinit var testBinder: TestService.TestBinder
    lateinit var mContext: Context;

    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        Log.i("TAG", "onServiceConnected")
        testBinder = service as TestService.TestBinder;
        testBinder.dragon(mContext)
    }

    override fun onServiceDisconnected(name: ComponentName?) {
        Log.i("TAG", "onServiceDisconnected")
    }

    fun getContext(context: Context) {
        mContext = context
    }
}
class MainActivity : AppCompatActivity() {

    private lateinit var btn_startService: Button
    private lateinit var btn_stopService: Button
    private lateinit var mServiceConnection: TestServiceConnection

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initView()
        initData()
        initClick()
    }

    private fun initView() {
        btn_startService = findViewById(R.id.btn_startService)
        btn_stopService = findViewById(R.id.btn_stopService)
    }

    private fun initData() {
        mServiceConnection= TestServiceConnection()
        mServiceConnection.getContext(applicationContext)
    }

    private fun initClick() {
        btn_startService.setOnClickListener {
            bindService(
                Intent(this, TestService::class.java),
                mServiceConnection,
                BIND_AUTO_CREATE
            )
        }
        btn_stopService.setOnClickListener {
            unbindService(mServiceConnection)
        }
    }

}

七、IntentService

private const val UPDATE_APP = "com.example.second.action.UpdateApp"

class DownloadService : IntentService("DownloadService") {

    override fun onHandleIntent(intent: Intent?) {
    	//执行耗时工作
        when (intent?.action) {
            UPDATE_APP -> {
                val url = intent.getStringExtra("updateApp")
                if (null != url) {
                    download(applicationContext, url)
                }
            }
        }
    }

    companion object {
        @JvmStatic
        fun startDownload(context: Context, url: String) {
            val intent = Intent(context, DownloadService::class.java).apply {
                action = UPDATE_APP
                putExtra("updateApp", url)
            }
            context.startService(intent)
        }
    }


    private fun download(context: Context, url: String) {
        val request = DownloadManager.Request(Uri.parse(url))
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "test.apk")
        request.setAllowedOverRoaming(false)
        request.setTitle("test")
        request.setDescription("version update")
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
        val downloadManager: DownloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        downloadManager.enqueue(request)
        context.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
    }

    private fun getDownloadPath(): String {
        val download: File = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
        if (!download.exists()) {
            download.mkdirs()
        }
        return download.path + "/test.apk"
    }


    private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val downloadManager = context.getSystemService(DOWNLOAD_SERVICE) as DownloadManager

            val downloadID = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)

            val query = DownloadManager.Query()

            query.setFilterById(downloadID)

            val cursor: Cursor = downloadManager.query(query)

            if (cursor.moveToFirst()) {
                val state = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))
                if (state == DownloadManager.STATUS_SUCCESSFUL) {
                    val intent = Intent(Intent.ACTION_VIEW)
                    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                    if (Build.VERSION.SDK_INT >= 24) {
                        val file= File(getDownloadPath())
                        if (!file.exists()) {
                            return
                        }
                        val apkUri = FileProvider.getUriForFile(
                            context,
                            context.packageName +".provider",
                            file
                        )
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                        intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
                    } else {
                        intent.setDataAndType(
                            Uri.fromFile(
                                File(
                                    context.getExternalFilesDir(
                                        Environment.DIRECTORY_DOWNLOADS
                                    ), "test"
                                )
                            ), "application/vnd.android.package-archive"
                        )
                    }
                    context.startActivity(intent)
                }
            }
            cursor.close()
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        //注销广播
        unregisterReceiver(receiver)
    }
}
        <service
            android:name=".DownloadService"
            android:exported="false" />

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path" />
        </provider>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http:/android:/schemas.android.com/apk/res/android">
    <!--res->xml->file_path.xml-->
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
 //调用
 DownloadService.startDownload(this,"下载路径")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值