Android Nougat PhoneStateListener 未被触发

Android Nougat PhoneStateListener is not triggered

在 Android(目标 25)中我有一个后台服务,在 onCreate 函数中我已经初始化了一个 phone 状态侦听器。它在 Nougat 之前的 Android 版本上工作正常,但在 Nougat 中它不起作用,即使授予了权限。

public class Service extends IntentService
{
    class PhoneListener extends PhoneStateListener
    {
       String TAG = getClass().getName();
       @Override
       public void onCallStateChanged(int state, String incomingNumber) 
       {
           super.onCallStateChanged(state, incomingNumber);
           switch (state)
           {
               case TelephonyManager.CALL_STATE_IDLE:
                Log.d(TAG,"IDLE" );
               break;
               case TelephonyManager.CALL_STATE_OFFHOOK:
                Log.d(TAG,"OFFHOOK");
               break;
               case TelephonyManager.CALL_STATE_RINGING:
                Log.d(TAG,"RINGING");
               break;
           }
       }
   }

   public Service ()
   {
       super("ChatService");
   }
   public Service(String name)
   {
       super(name);
   }

   @Override
   public void onCreate()
   {
       super.onCreate();
       TelephonyManager tm = (TelephonyManager)getApplicationContext().getSystemService(TELEPHONY_SERVICE);
       PhoneListener listener = new PhoneListener();
       tm.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
   }
}

我不知道是什么问题,电话管理器似乎没有注册,因此没有触发 onCallStateChanged。 我的猜测之一是在 Android M 上引入的 Doze 功能,但仍然.. 即使找不到 phone "in work",此代码在 Android 6 上也能正常工作

所以对于那些遇到同样问题的人,我找到了解决方案。 您不需要为 PhoneState 注册 BroadcastReceiver

因此,我没有在 onCreate 方法(服务的)中注册电话管理器来监听,而是在 onStartCommand 中设置它并它开始工作了。

但请注意,在任何情况下 onStartCommand 都会被触发,它会注册电话管理器,所以一定要只注册一次。

在我的例子中,因为在服务 class 中我有内部 class PhoneListener 我创建了一个 class 成员并初始化了它为 null,并且在 onStartCommand 中我检查了它是否为 null,然后创建并注册了电话管理器,但是您可以使用 singelton 方式。

所以这是我的代码,它也适用于 Android 牛轧糖:

public class Service extends IntentService
{
    class PhoneListener extends PhoneStateListener
    {
       String TAG = getClass().getName();
       @Override
       public void onCallStateChanged(int state, String incomingNumber) 
       {
           super.onCallStateChanged(state, incomingNumber);
           switch (state)
           {
               case TelephonyManager.CALL_STATE_IDLE:
                  Log.d(TAG,"IDLE" );
               break;
               case TelephonyManager.CALL_STATE_OFFHOOK:
                   Log.d(TAG,"OFFHOOK");
               break;
               case TelephonyManager.CALL_STATE_RINGING:
                   Log.d(TAG,"RINGING");
               break;
           }
     }
     PhoneListener phoneListener = null;

     public Service ()
     {
       super("ChatService");
     }

     @Override
     public void onCreate()
     {
        super.onCreate();
        // do what you need here
     }

     @Override
     public int onStartCommand (Intent intent, int flags, int startId)
     {
        if (phoneListener == null)
        {
          TelephonyManager tm = (TelephonyManager)getApplicationContext().getSystemService(TELEPHONY_SERVICE);
          phoneListener = new PhoneListener();
          tm.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
        }
        // do what you need to do here

        return START_STICKY; // you can set it as you want
     } 
 }

这是由于 https://github.com/aosp-mirror/platform_frameworks_base/commit/f5d7c587e86c64e657a15a12ad70e75d47c48d99#diff-5af2ac899de823cf60597e554bf67fe0 对 PhoneStateListener 进行了更改。

PhoneStateListener 的本地引用仅通过弱引用在内部进行跟踪。这使得它有资格在函数退出时进行垃圾收集,一旦侦听器完成,应用程序将不会收到任何进一步的更新。解决方案是通过 class 成员变量保留对 PhoneStateListener 的引用。