调用前台服务时应用程序崩溃[重复]

Posted

技术标签:

【中文标题】调用前台服务时应用程序崩溃[重复]【英文标题】:App crashing when calling foreground service [duplicate] 【发布时间】:2021-09-26 13:44:30 【问题描述】:

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

堆栈跟踪

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(): ServiceRecorddac122 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)

我的代码

活动

    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)

    

服务

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
                )
            
        
    

【问题讨论】:

使用 Logcat 检查与您的崩溃相关的堆栈跟踪。 @CommonsWare 我添加了堆栈跟踪 每个前台服务都需要一个通知并且它必须满足特定的标准(意味着它不能为空等) 启动服务的activity是否在后台? @TomTaylor 启动服务后,我完成了活动 【参考方案1】:

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

Check the information here

新的 Context.startForegroundService() 方法启动前台服务。即使应用在后台,系统也允许应用调用 Context.startForegroundService()。但是,应用程序必须在服务创建后五秒内调用该服务的 startForeground() 方法。

【讨论】:

以上是关于调用前台服务时应用程序崩溃[重复]的主要内容,如果未能解决你的问题,请参考以下文章

接收新的FCM消息(前台和后台)时Android应用程序崩溃

ZombieJS:从 for 循环重复调用时间歇性崩溃

进入前台时应用程序崩溃

尝试在后台/前台运行时应用程序崩溃但适用于其他手机

Xcode 9.3 使用 URL 方案(深度链接)调用时构建崩溃 [重复]

调用核心数据操作时出现“未能及时更新场景”消息崩溃