0

1) 我正在开始ServiceJobService通过startService,startForegroundService对于 android Oreo 和ContextCompat.startForegroundService

2)在onCreate 我做的服务的方法中startForeground (1, notification),在onDestroy我做的stopForeground (false)

onCreateservice 方法中,BroadcastReceiver启动,接收TelephonyManager.EXTRA_STATE诸如 OFFHOOK、RINGING、IDLE 之类的事件

这是注册接收器的代码

applicationContext.registerReceiver (
    broadcastReceiver, 
    IntentFilter (TelephonyManager.ACTION_PHONE_STATE_CHANGED),
    Manifest.permission.CALL_PHONE, null)

启动服务后,我立即致电

    val intent = Intent (Intent.ACTION_DIAL)
    intent.data = Uri.parse ("tel: +77787020453")
    startActivity (intent)

我开始打电话

我进入服务日志

18: 38: 17.008 I / main >>>>: Unstoppable: onCreate
18: 38: 17.013 4371-4371 / me.myapp I / main >>>>: UnstoppableJob: onStartCommand
18: 38: 17.231 4371-5110 / me.myapp I / main >>>>: Unstoppable - 1
18: 38: 18.730 4371-5110 / me.myapp I / main >>>>: Unstoppable - 2
18: 38: 19.082 4371-4371 / me.myapp I / Unstoppable: blockCallReciever: onRecieve:
18: 38: 19.082 4371-4371 / me.myapp I / Unstoppable: android.intent.action.PHONE_STATE = OFFHOOK
18: 38: 21.715 5169-5169 /? I / main >>>>: Unstoppable: onCreate ⁉️
18: 38: 21.741 5169-5169 /? I / main >>>>: UnstoppableJob: onStartCommand
18: 38: 21.947 5169-5231 /? I / main >>>>: Unstoppable - 1 ⁉️
18: 38: 24.114 5242-5242 / me.myapp I / main >>>>: Unstoppable: onCreate
18: 38: 24.145 5242-5242 / me.myapp I / main >>>>: UnstoppableJob: onStartCommand

Unstoppable - 1, Unstoppable - 2 - 这是我开始查看服务是否实时运行的计时器。

我不明白为什么服务onCreate再次调用而不调用onDestroy,谁能帮我解决这个问题并在拨打电话时使服务稳定工作?

服务代码

package me.test.ui.test.job

import android.Manifest
import android.annotation.TargetApi
import android.app.Service
import android.content.*
import android.os.Build
import android.os.IBinder
import android.telephony.PhoneNumberUtils
import android.telephony.TelephonyManager
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import io.reactivex.Completable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import me.testapp.TestApp
import me.testapp.SyncedTime
import me.testapp.entity.CallLogItemPojo
import me.testapp.entity.CallLogPhoneStatePojo
import me.testapp.entity.PhoneStateString
import me.testapp.interactors.ContactsInteractor
import me.testapp.interactors.LoginScreenInteractor
import me.testapp.interactors.TaskInteractor
import me.testapp.managers.BlockedTelephonyManager
import me.testapp.managers.SettingsManager
import me.testapp.ui.test.TestActivity
import me.testapp.ui.test.TestActivity.Companion.log
import java.lang.Exception
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class UnstoppableJob : Service() {
    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    private lateinit var timer: Timer

    private var TAG = "Unstoppable"
    private var timerTask = object : TimerTask() {
        override fun run() {
            var lifetimeOfTask = preferences.getLong(SettingsManager.TASK_LIFETIME_MILLIES, 0)

            if (lifetimeOfTask != 0.toLong() && lifetimeOfTask < System.currentTimeMillis()) {
                stopSelf()
                log(message = "Unstoppable: stopSelf")
            }
            log(message = "Unstoppable - $count")
            count++

        }

    }

    @Inject
    lateinit var loginInteractor: LoginScreenInteractor

    @Inject
    lateinit var interactor: TaskInteractor

    private var count = 1
    @Inject
    lateinit var preferences: SharedPreferences

    private var dispose: Disposable? = null
    private val disposable = CompositeDisposable()

    @Inject
    lateinit var contactsInteractor: ContactsInteractor

    private val listPhoneState = LinkedList<PhoneStateString>()
    private var phoneNumber: String? = null
    private var id: Int? = null
    private var token: String? = null
    private var type: String? = null
    private var callTypeForReceiver: String? = null

    private val phoneList = mutableListOf<String>()
    private val idListOfTask = mutableSetOf<Int>()
    private val timeMap = mutableMapOf<Int, Disposable>()


    private val blockCallReciever = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            Log.i(TAG, "blockCallReciever: onRecieve:")
            var lifetimeOfTask = preferences.getLong(SettingsManager.TASK_LIFETIME_MILLIES, 0)

            Log.i(
                TAG, intent?.action + " " + intent?.getStringExtra(
                TelephonyManager.EXTRA_STATE) + " " + intent?.getStringExtra(
                TelephonyManager.EXTRA_STATE_RINGING))

            if (intent == null || intent.action != "android.intent.action.PHONE_STATE") {
                return
            }

            val callNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)

            //val number = intent?.getStringExtra(TelephonyManager.EXTRA_)
            val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)

            if (callNumber != null && callNumber.isNotEmpty()) {
                var it = PhoneStateString(callNumber, state, Date())
                listPhoneState.add(it)

                // Send CDR
                if (it.state == "IDLE" &&
                    lifetimeOfTask >= System.currentTimeMillis()) {
                    Log.i(TAG, "TestApplistener: IDLE send cdr")
                    sendCDR()
                }


                Log.i(TAG, "RingApplistener: ${it.state == "RINGING"} && ${preferences.getBoolean(SettingsManager.AUTO_RESET_CALLS, false)} && ${lifetimeOfTask >= System.currentTimeMillis()}")
                if (it.state == "RINGING" &&
                    preferences.getBoolean(SettingsManager.AUTO_RESET_CALLS, false) &&
                    lifetimeOfTask >= System.currentTimeMillis()) {
                    var isCallEnded = BlockedTelephonyManager.findHandler(applicationContext!!).endCall()
                    Log.i(TAG, "RingApplistener: auto reset call: isCallEnded=$isCallEnded")

                    // TODO: check it
                    if (type != null && type == "incoming" && callTypeForReceiver != null && callTypeForReceiver == "decline_call") {
                        val isCallEnded = BlockedTelephonyManager.findHandler(applicationContext!!).endCall()
                        Log.i(TAG, "RingApplistener: auto reset call: isCallEnded=$isCallEnded")
                    }


                }
            }

            Log.d(TAG, "blockCallReciever: onRecieve - number $callNumber, state: $state")
        }

    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private fun sendCDR() {
        val bufList = mutableListOf<PhoneStateString>()
        do {
            bufList.add(listPhoneState.pop())
        } while (bufList.last().state != "IDLE")

        if (bufList.isNotEmpty()) {
            dispose = contactsInteractor.loadLastCallLog(phoneNumber).flatMapCompletable {
                val list = if (!phoneNumber.isNullOrEmpty())
                    it.filter { PhoneNumberUtils.normalizeNumber(it.number) == PhoneNumberUtils.normalizeNumber(
                        phoneNumber
                    )
                    }
                else
                    it
                list.map { it.callLogPhoneState = CallLogPhoneStatePojo(bufList) }
                Log.i(TAG, "TestAppListenerService: $token $id sendCdr ${list.toString()}")

                if (token == null || id == null) {
                    Completable.error(Throwable("null"))
                } else {
                    interactor.sendCdr(token!!, id!!, CallLogItemPojo(list))
                }

            }.subscribe({
                Log.i(TAG, "TaskPresenter: " + "successful")
            }, {
                Log.i(TAG, "TaskPresenter: " + "unsuccessful ${it.message}")
            })
        }
    }

    override fun onCreate() {
        super.onCreate()
        log(message = "Unstoppable: onCreate")

        timer = Timer()
        timer.schedule(timerTask, 222, 1500)

        TestApp.component.inject(this)

        applicationContext.registerReceiver(blockCallReciever, IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED),
            Manifest.permission.CALL_PHONE, null)


        val notification = NotificationCompat.Builder(this, TestApp.CHANNEL_ID)
            .setContentTitle("TestApp")
            .setContentText("Foreground service")
            .build()

        startForeground(1, notification)
    }


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        TestActivity.log(message = "UnstoppableJob: onStartCommand")
        if (intent?.extras != null) {
            intent.extras!!.also {
                val buf = it
                buf.keySet().forEach {
                    Log.i(TAG ,"Command: $it = ${buf.get(it)}")
                }
                if (it.containsKey("exit")) {
                    disposable.dispose()
                    dispose?.dispose()
                    this@UnstoppableJob.stopSelf()
                    stopSelf()
                }

                if (it.containsKey("phoneNumber")) {
                    phoneNumber = it.getString("phoneNumber")
                    if (phoneNumber != null) {
                        phoneList.add(phoneNumber!!)
                    }
                }

                if (it.containsKey("id"))  id = it.getInt("id")
                if (it.containsKey("token")) token = it.getString("token")
                if (it.containsKey("type")) type = it.getString("type")
                if (it.containsKey("callTypeForReceiver")) callTypeForReceiver = it.getString("callTypeForReceiver")

                if (it.getBoolean("delete", false)) {
                    removeTask(it.getInt("id"))
                }
                if (it.containsKey("ringing") && it.containsKey("id")) {
                    SyncedTime.requestTimeFromTestApp()
                    if (!idListOfTask.contains(it.getInt("id"))) {
                        timeMap[it.getInt("id")] = Completable.complete().delay(60, TimeUnit.SECONDS).subscribe {
                            removeTask(it.getInt("id"))
                        }
                    }

                    idListOfTask.add(it.getInt("id"))
                }
            }
        }

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

    private fun removeTask(id: Int) {
        Log.i(TAG,"remove tasks by $id")
        idListOfTask.remove(id)
        if (idListOfTask.size == 0) {
            dispose?.dispose()
            disposable.dispose()
            onClear()
        }
    }

    fun onClear() {
        disposable.dispose()
        timeMap.values.forEach {
            it.dispose()
        }
        this@UnstoppableJob.stopSelf()
    }


    override fun bindService(service: Intent?, conn: ServiceConnection, flags: Int): Boolean {
        return super.bindService(service, conn, flags)
    }

    override fun unbindService(conn: ServiceConnection) {
        super.unbindService(conn)
    }


    override fun onDestroy() {
        super.onDestroy()
        TestActivity.log(message = "UnstoppableJob: onDestroy")

        try {
            timer.cancel()
            timerTask.cancel()
            count = 1
        } catch (e: Exception) {

            log(message = "Unstoppable: onDestroy - error cancel timer: ${e.message}")
        }


        dispose?.dispose()
        disposable.dispose()

        applicationContext.unregisterReceiver(blockCallReciever)

        var restoreServiceIntent = Intent("con.raone.start.serivce")
        restoreServiceIntent.putExtra("startService", true)
        sendBroadcast(restoreServiceIntent)

        stopForeground(false)
    }

}
4

1 回答 1

0

我通过在清单文件中注册 Broadcastreceiver 解决了这个问题。

    <receiver
        android:name=".broadcast.ReadPhoneStateReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
    </receiver>
于 2019-12-01T15:30:33.180 回答