调用前台服务时应用程序崩溃

App crashing when calling foreground service

我正在尝试调用 startForegroundService(intent),但我的应用程序在几秒钟后崩溃了,但我可以在我的另一个 activity 中调用 startForegroundService(intent) 它工作正常并且两个活动具有相同的代码.我无法弄清楚是什么导致了这个问题。我正在尝试在 activity 中上传一些照片,其中一张没有任何问题,而在这张 activity 中,它在我点击按钮

几秒钟后崩溃了

堆栈跟踪

2021-07-18 22:48:16.233 8352-8352/com.android.testproject1 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.testproject1, PID: 8352
    android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{dac122 u0 com.android.testproject1/.services.UploadServiceOffers}
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2005)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

我的代码

Activity

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId==R.id.Post){


            if (descriptionTextTitle.text.isEmpty()) {
//                AnimationUtil.shakeView(mEditText, activity)

            } else {

                sharedPreferences.edit().putInt("count", ++serviceCount).apply()
                Log.d(myTag, "On click  sp $serviceCount")

                val intent = Intent(this, UploadServiceOffers::class.java)

                intent.putExtra("count", serviceCount)

                intent.putExtra("notification_id", System.currentTimeMillis().toInt())

                intent.action = UploadServiceOffers.ACTION_START_FOREGROUND_SERVICE_UPLOAD_OFFERS

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    startForegroundService(intent)

                    Log.d(myTag, "Build Version OP")
//                startForegroundService(activity!!,intent)
                } else {

                    Log.d(myTag, "Build Version NP")
//                activity!!.startService(intent)
                    startService(intent)
                }
                Toasty.info(this, "Uploading images..", Toasty.LENGTH_SHORT, true).show()
                finish() 

            }


        }

        return super.onOptionsItemSelected(item)

    }

Service

class UploadServiceOffers : Service() {


    companion object{
        val ACTION_START_FOREGROUND_SERVICE_UPLOAD_OFFERS = "ACTION_START_FOREGROUND_SERVICE"
    }
    private var count = 0
    private var bitmap: Bitmap? = null
    private var resized: Bitmap? = null
    val myTag:String = "MyTag"



    override fun onCreate() {
        Log.d(myTag, "Service Created ")
        super.onCreate()

    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

        Log.d(myTag, "onStart $intent   $flags  $startId")

        if (intent!=null) {
            val action = intent.action
            if (action == ACTION_START_FOREGROUND_SERVICE_UPLOAD_OFFERS) {

                val imagesList: ArrayList<Image>? = intent.getParcelableArrayListExtra<Image>("imagesList")

                val notificationId = intent.getIntExtra("notification_id", 3)

                val postID = intent.getStringExtra("offerID")

                val title=intent.getStringExtra("title")

                val originalPrice=intent.getStringExtra("originalPrice")

                val discountedPrice=intent.getStringExtra("discountedPrice")

                val city=intent.getStringExtra("city")

                val currentId = intent.getStringExtra("current_id")

                val description = intent.getStringExtra("description")

                val uploadedImagesUrl = intent.getStringArrayListExtra("uploadedImagesUrl")

                count = intent.getIntExtra("count", 0)

                if (imagesList != null) {
                    if (postID != null) {
                        if (title != null) {
                            if (city != null) {
                                if (originalPrice != null) {
                                    if (discountedPrice != null) {
                                        uploadImages(notificationId, 0, imagesList, currentId, description,
                                            uploadedImagesUrl, postID,title,originalPrice,discountedPrice,city)
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }


        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
    }

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

    private fun stopForegroundService(removeNotification: Boolean) {

        Log.d(myTag,"Stop foreground service.")
        // Stop foreground service and remove the notification.
        stopForeground(removeNotification)
        // Stop the foreground service.
        stopSelf()
    }

    private fun notifyProgress(
        id: Int,
        icon: Int,
        title: String,
        message: String,
        context: Context,
        max_progress: Int,
        progress: Int,
        indeterminate: Boolean
    ) {
        val builder = NotificationCompat.Builder(context, App.CHANNEL_ID2)
//         Create notification default intent.
        val intent = Intent()
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
        builder.setSmallIcon(icon)
            .setContentTitle(title)
            .setContentText(message)
            .setOngoing(true)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .setTicker(message)
            .setChannelId(App.CHANNEL_ID2)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setProgress(max_progress, progress, indeterminate)
            .setVibrate(LongArray(0))
        startForeground(id, builder.build())

    }


    fun getImageUri(inContext: Context, inImage: Bitmap) {
        val bytes = ByteArrayOutputStream()
        inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
        var path: String?=null
        try {
            path = MediaStore.Images.Media.insertImage(inContext.contentResolver, inImage, "Title", null)

        }catch (e: java.lang.Exception){
            e.localizedMessage?.toString()?.let { Log.d(myTag, it) }
        }
        if (path!=null){
            Log.d(myTag, Uri.parse(path).toString())
        }
        else{
            Log.d(myTag, "Path is null ")
        }


    }


    private fun uploadImages(
        notification_id: Int,
        index: Int,
        imagesList: ArrayList<Image>,
        currentUser_id: String?,
        description: String?,
        uploadedImagesUrl: ArrayList<String>?,
        postID:String,
        title: String,
        originalPrice:String,
        discountPrice:String,
        city:String
    ) {
        val imgCount = index + 1

        var imageUri: Uri

        val imageUri0: Uri?= Uri.fromFile(File(imagesList[index].path))

        if (Build.VERSION.SDK_INT >= 29) {
            try {
                bitmap = imageUri0?.let { ImageDecoder.createSource(this.contentResolver,it)}?.let { ImageDecoder.decodeBitmap(it) }
            } catch (e: IOException) {
                e.printStackTrace()

                e.localizedMessage?.toString()?.let { Log.d(myTag, " errore is  $it") }
            }
        } else {
            // Use older version
            try {
                bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, imageUri0)
            } catch (e: IOException) {
                e.printStackTrace()
                e.localizedMessage?.toString()?.let { Log.d(myTag, " errore is  $it") }
            }
        }

//        val bitmap = BitmapFactory.decodeFile(file.getAbsolutePath())

        resized = bitmap?.let { Bitmap.createScaledBitmap(it, 600, 600, true) }
//        Log.d(myTag, "path is  ${bitmap.toString()}")

        var path :String?=null
        try {
//            path = MediaStore.Images.Media.insertImage(this.contentResolver, resized, "Title", null)
            path = MediaStore.Images.Media.insertImage(this.contentResolver, resized,  "IMG_"
                    + System.currentTimeMillis(), null)
            Log.d(myTag, "path is  $path")
        }catch (e :java.lang.Exception){
            Log.d(myTag, "path is exception $path" )
            Log.d(myTag, e.localizedMessage.toString() )

        }


        imageUri = Uri.parse(path)


//        imageUri = try {
//
//            val compressedFile: File = id.zelory.compressor.Compressor()
//                .setQuality(80)
//                .setCompressFormat(Bitmap.CompressFormat.JPEG)
//                .compressToFile(File(imagesList[index].path))
//            Uri.fromFile(compressedFile)
//        } catch (e: Exception) {
//            e.printStackTrace()
//            Uri.fromFile(File(imagesList!![index].path))
//        }


        val fileToUpload =
            currentUser_id?.let {
                FirebaseStorage.getInstance().reference.child("Offers").child(it)
                    .child(postID)
                    .child("Voila_"+ System.currentTimeMillis() + "_" + imagesList[index].name)
            }
        fileToUpload?.putFile(imageUri)?.addOnSuccessListener {
            Log.d(myTag, "Uploaded Successfully")
            fileToUpload.downloadUrl
                .addOnSuccessListener { uri: Uri ->
                    uploadedImagesUrl!!.add(uri.toString())
                    val nextIndex = index + 1
                    try {
                        if (!TextUtils.isEmpty(imagesList[index + 1].path)) {
                            uploadImages(
                                notification_id,
                                nextIndex,
                                imagesList,
                                currentUser_id,
                                description,
                                uploadedImagesUrl,
                                postID,
                                title,originalPrice, discountPrice,city)
                        } else {
                            uploadPost(
                                notification_id,
                                currentUser_id,
                                description,
                                uploadedImagesUrl,
                                postID,
                                title,originalPrice,discountPrice,city)
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                        uploadPost(
                            notification_id,
                            currentUser_id,
                            description,
                            uploadedImagesUrl, postID,
                            title, originalPrice, discountPrice,city)
                    }
                }
                .addOnFailureListener { obj: Exception -> obj.printStackTrace() }
        }?.addOnFailureListener { obj: Exception ->
            obj.printStackTrace()
            obj.localizedMessage?.toString()?.let { Log.d(myTag, "Exception is  $it") }
        }?.addOnProgressListener { taskSnapshot: UploadTask.TaskSnapshot ->
            if (count == 1) {
                val title = "Uploading " + imgCount + "/" + imagesList.size + " images..."
                val progress = (100.0 * taskSnapshot.bytesTransferred / taskSnapshot.totalByteCount).toInt()

                notifyProgress(notification_id, R.drawable.stat_sys_upload, title, "$progress%",
                    applicationContext, 100, progress, true)
            } else if (count > 1) {
                notifyProgress(
                    notification_id,
                    R.drawable.stat_sys_upload,
                    "Viola",
                    "Uploading $count posts",
                    applicationContext,
                    100,
                    0,
                    true
                )
            }
        }
    }
}

为了避免应用程序崩溃,您必须在 onStartCommand 方法中调用 startForeground(notification) 以立即或在服务启动后立即显示通知。

Check the information here

The new Context.startForegroundService() method starts a foreground service. The system allows apps to call Context.startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created.