简体   繁体   中英

Making app service work invisible in background

i have an app that runs a background service infinitely while also hiding the app icon and hiding it from the backstack so it wont be visible to the user while running using:

       val componentName = ComponentName(this, FullscreenActivity::class.java)
       p.setComponentEnabledSetting(
           componentName,
           PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
           PackageManager.DONT_KILL_APP
       )

this is how i launch the service from my fragment:

parentFragment?.activity?.startService(
                    Intent(
                        requireParentFragment().requireActivity().applicationContext,
                        RescueService::class.java
                    ).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                )

which successfully hides the icon and the app from backstack and the service keep running, also when i press the square button on my phone to show the backstack apps running i dont see the app there which is what i want, but if i click the "X" button to clear all backstack apps it also kills my app and my service dies even though the app does not appear there as i mentioned.

Any ideas what makes the service die after doing it? because it did not happen to couple of days ago before i did some changes in my app..

One of the changes i made is turnning my Service into LifecycleService because i needed my service to observe a livedata which needs a LifecycleOwner .Can it be the cause of my service to die when clearing the backstack?

All suggestions will be welcomed !

EDIT1 - here is my TestService that performs voice recording uses WorkManager .I call hideApp() to hide the icon from the phone and make the app invisible from the backstack:

class RecordingWork(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override val coroutineContext = Dispatchers.Main
    override suspend fun doWork(): Result {

        mSpeechRecognizer.startListening(mSpeechRecognizerIntent)
        return Result.success()
    }
}

private lateinit var mSpeechRecognizer: SpeechRecognizer
private val mSpeechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)

class TestService : Service() {

    private lateinit var workManager: WorkManager

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d("TestService", "onStartCommand called")
        hideApp()
        prepareVoiceRecording()
        workManager = WorkManager.getInstance(applicationContext)
        workManager.enqueue(OneTimeWorkRequestBuilder<RecordingWork>().build())

        return START_REDELIVER_INTENT
    }

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

    fun prepareVoiceRecording() {
        mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(applicationContext)
        mSpeechRecognizerIntent.putExtra(
            RecognizerIntent.EXTRA_LANGUAGE_MODEL,
            RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
        )
        mSpeechRecognizerIntent.putExtra(
            RecognizerIntent.EXTRA_LANGUAGE,
            Locale.getDefault()
        )
        mSpeechRecognizer.setRecognitionListener(
            object : RecognitionListener {

                @RequiresApi(Build.VERSION_CODES.M)
                override fun onError(i: Int) {
                    Log.d(TAG, "onErrorCalled error is $i")
                    if (i == SpeechRecognizer.ERROR_NETWORK || i == SpeechRecognizer.ERROR_SPEECH_TIMEOUT || i == SpeechRecognizer.ERROR_NO_MATCH) {
                        Log.d(TAG, "error triggered")
                        mSpeechRecognizer.destroy()
                        prepareVoiceRecording()
                        workManager.enqueue(OneTimeWorkRequestBuilder<RecordingWork>().build())

                    }
                }

                @RequiresApi(Build.VERSION_CODES.M)
                override fun onResults(bundle: Bundle) {
                    Log.d(TAG, "onResults Called")
                    //getting all the matches
                    val matches = bundle
                        .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)!!
                    workManager.enqueue(OneTimeWorkRequestBuilder<RecordingWork>().build())
                }

 private fun hideApp() {
        val componentName = ComponentName(
            this,
            WelcomeScreenActivity::class.java
        )
        packageManager.setComponentEnabledSetting(
            componentName,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
        )
    }

this service does work to repeatedly record voice by rescheduling the Worker every time. but this service also dies when clearing backstack (even though the app does not appear there because of hideApp() )

Use workManager for long running background task (some device like Mi phone you need to white list the app for battery saver if you don't do that the OS will kill your app) and hiding of app icon not work in android X (only system apps can hide their icon)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM