Service

示例ServiceTest

MainActivity:

package com.example.servicetest

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.widget.Button
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

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?) {
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val startServiceBtn=findViewById<Button>(R.id.startServiceBtn)
        val stopServiceBtn=findViewById<Button>(R.id.stopServiceBtn)
        val bindServiceBtn=findViewById<Button>(R.id.bindServiceBtn)
        val unbindService=findViewById<Button>(R.id.unbindService)
        val startIntentServiceBtn=findViewById<Button>(R.id.startIntentServiceBtn)

        startServiceBtn.setOnClickListener {
            val intent=Intent(this,MyService::class.java)
            startService(intent)
        }
        stopServiceBtn.setOnClickListener {
            val intent=Intent(this,MyService::class.java)
            stopService(intent)
        }
        bindServiceBtn.setOnClickListener {
            val intent=Intent(this,MyService::class.java)
            bindService(intent,connection,Context.BIND_AUTO_CREATE)//绑定Service
        }
        unbindService.setOnClickListener {
            unbindService(connection)
        }
        startIntentServiceBtn.setOnClickListener {
            Log.d("MainActivity", "Thread id is ${Thread.currentThread().name}")
            val intent=Intent(this,yzlIntentService::class.java)
            startService(intent)
        }
    }
}

activity_main布局:

<?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:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/startServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service"/>

    <Button
        android:id="@+id/stopServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service"/>

    <Button
        android:id="@+id/bindServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind Service"/>

    <Button
        android:id="@+id/unbindService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind Service"/>

    <Button
        android:id="@+id/startIntentServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start IntentService"/>

</LinearLayout>

yzlIntentActivity:

package com.example.servicetest

import android.app.IntentService
import android.content.Intent
import android.util.Log

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

        //在这个方法中可以处理一些耗时逻辑,不会ANR
    }

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

示范代码

MainActivity:

package com.example.servicewyr

import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import java.io.FileNotFoundException

class MainActivity : AppCompatActivity() {

    private lateinit var imageView: ImageView
    private lateinit var selectedImageUri: Uri
    private var factor = 1.0f
    val fromAlbum = 1

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

        imageView = findViewById(R.id.imageView)
        val fromAlbumBtn: Button = findViewById(R.id.takePhotoBtn)
        val processButton: Button = findViewById(R.id.processButton)
        fromAlbumBtn.setOnClickListener {
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = "image/*"
            startActivityForResult(intent, fromAlbum)
        }

        processButton.setOnClickListener {
            startService(Intent(this, ImageProcessingService::class.java).apply {
                putExtra("factor", factor)
                putExtra("selectedImageUri", selectedImageUri.toString())
            })
        }

        val seekBar: SeekBar = findViewById(R.id.SeekBar01)
        seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                factor = progress / 100f
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit
            override fun onStopTrackingTouch(seekBar: SeekBar?) = Unit
        })
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == fromAlbum && resultCode == Activity.RESULT_OK && data != null) {
            selectedImageUri = data.data!!
            val bitmap = getBitmapFromUri(selectedImageUri)
            imageView.setImageBitmap(bitmap)
        }
    }

    private fun getBitmapFromUri(uri: Uri): Bitmap {
        return contentResolver.openInputStream(uri)?.use { input ->
            BitmapFactory.decodeStream(input)
        } ?: throw FileNotFoundException("File not found for the Uri: $uri")
    }

    private val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "imageProcessed") {
                val processedBytes = intent.getByteArrayExtra("processedBitmap")
                val processedBitmap =
                    processedBytes?.let { BitmapFactory.decodeByteArray(processedBytes, 0, it.size) }
                imageView.setImageBitmap(processedBitmap)
            }
        }
    }

    override fun onResume() {
        super.onResume()
        val filter = IntentFilter("imageProcessed")
        registerReceiver(broadcastReceiver, filter)
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(broadcastReceiver)
    }
}

onResumeonPause是Android生命周期方法,分别在活动可见和不可见时调用。在onResume中注册BroadcastReceiver,在onPause中注销,以防止内存泄漏。

ImageProcessingService:

package com.example.servicewyr

import android.app.IntentService
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import android.net.Uri
import java.io.ByteArrayOutputStream
import java.io.FileNotFoundException
import java.io.InputStream

class ImageProcessingService : IntentService("ImageProcessingService") {

    override fun onHandleIntent(intent: Intent?) {
        val factor = intent?.getFloatExtra("factor", 1.0f)
        val imageUriStr = intent?.getStringExtra("selectedImageUri")
        val imageUri = Uri.parse(imageUriStr)

        val originalBitmap = getBitmapFromUri(imageUri)

        val processedBitmap = processImageWithFactor(factor ?: 1.0f, originalBitmap ?: return)

        val broadcastIntent = Intent("imageProcessed")
        val byteArray = convertBitmapToBytes(processedBitmap)
        broadcastIntent.putExtra("processedBitmap", byteArray)
        sendBroadcast(broadcastIntent)
    }


    private fun getBitmapFromUri(uri: Uri): Bitmap {
        return contentResolver.openInputStream(uri)?.use { input ->
            BitmapFactory.decodeStream(input)
        } ?: throw FileNotFoundException("File not found for the Uri: $uri")
    }

    private fun processImageWithFactor(factor: Float, originalBitmap: Bitmap): Bitmap {
        val colorMatrix = ColorMatrix().apply {
            setScale(factor, factor, factor, 1f)
        }
        val paint = Paint().apply {
            colorFilter = ColorMatrixColorFilter(colorMatrix)
        }
        val processedBitmap = Bitmap.createBitmap(originalBitmap.width, originalBitmap.height, originalBitmap.config)
        val canvas = android.graphics.Canvas(processedBitmap)
        canvas.drawBitmap(originalBitmap, 0f, 0f, paint)
        return processedBitmap
    }

    private fun convertBitmapToBytes(bitmap: Bitmap): ByteArray {
        val outputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        return outputStream.toByteArray()
    }

    companion object {
        const val FACTOR_KEY = "factor"
        const val SELECTED_IMAGE_URI_KEY = "selectedImageUri"
        const val BITMAP_KEY = "processedBitmap"
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值