2015-07-29 7 views
0

Моя компания производит SDK, поставляемый в качестве файла aar для Android. В рамках этого SDK, мы определяем службу:bindService никогда не вызывает onServiceConnected

<service 
     android:name=".session.internal.ChatSession" 
     android:description="@string/description" 
     android:enabled="true" 
     android:exported="false" 
     android:label="Network communication service" 
    /> 

Эта услуга затем запускается и обязательность получения дополнительной кода в SDK:

public boolean bindService(final Runnable whenBound) { 
    if (connection == null) { 
     // Make sure the service is running 
     boolean success = startService(); 
     if(BuildConfig.DEBUG && !success) { 
      throw new AssertionError("startService failed"); 
     } 

     connection = new ServiceConnection() { 
      @Override 
      public void onServiceConnected(ComponentName name, IBinder service) { 
       chatSession = (IChatSession) service; 
       if(whenBound != null) { 
        whenBound.run(); 
       } 
      } 

      @Override 
      public void onServiceDisconnected(ComponentName name) { 
       chatSession = null; 
       connection = null; 
      } 
     }; 

     success = context.bindService(new Intent(context, ChatSession.class), connection, Context.BIND_IMPORTANT); 
     if(BuildConfig.DEBUG && !success) { 
      throw new AssertionError("bindService failed"); 
     } 

     return success; 
    } 

    if(whenBound != null) { 
     whenBound.run(); 
    } 

    return true; 
} 

boolean startService() { 
    boolean success = true; 

    if(!isServiceRunning()) { 
     success = context.startService(new Intent(context, ChatSession.class)) != null; 
    } 
    return success; 
} 

Это все работает отлично до тех пор, пока существует только один приложение с использованием SDK, установленного на мобильном устройстве.

Поскольку услуга является явно не экспортируется (android:exported="false") и неявно не экспортируются (нет <intent-filter> определена), мы ожидали, что это прекрасно работать с несколькими приложениями, установленных, а также, с каждым приложением получить его собственный, частный, экземпляр услуга, когда вызывается bindService.

Что на самом деле происходит то, что ни одно из приложений работает больше как ни ServiceConnection.onServiceConnected или ServiceConnected.onServiceDisconnected когда-либо называется, хотя призывы к context.startService и context.bindService возвращают успех.

Как только оба приложения были установлены, единственный способ заставить любой из них работать - это удалить оба, а затем переустановить только один. Недостаточно деинсталлировать самостоятельно.

+0

Это странно. Если вы когда-либо создадите пару проектов, которые воспроизводят эту проблему и публикуют источник для нее, сообщите мне, поскольку мне было бы интересно попробовать ее. – CommonsWare

+0

Это действительно странно. Вы не используете вспомогательные службы, поэтому нет способа привязываться к сервису в другом приложении. – jakubbialkowski

+0

@jakubbialkowski. AIDL имеет мало общего с привязкой к локальному/удаленному сервису. – pskink

ответ

0

Оказывается, проблема была на самом деле это бит код, который предотвращает службу от того начала, в первую очередь:

if(!isServiceRunning()) { 
    success = context.startService(new Intent(context, ChatSession.class)) != null; 
} 

я списан кодом isServiceRunning, что неправильно определит, что услуга была работает только на основе имени:

public boolean isServiceRunning() { 
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 
    List<ActivityManager.RunningServiceInfo> services = manager.getRunningServices(Integer.MAX_VALUE); 
    if(services == null) { 
     return false; 
    } 
    for (ActivityManager.RunningServiceInfo service : services) { 
     if (ChatSession.class.getName().equals(service.service.getClassName())) { 
      return true; 
     } 
    } 
    return false; 
} 

Замена если с:

 if (Process.myPid() == service.pid && ChatSession.class.getName().equals(service.service.getClassName())) { 

, похоже, решает проблему.

Я все еще не в восторге от этого, поскольку кажется, что должен быть лучший способ проверки.

+0

, вы действительно можете удалить 'isServiceRunning', вам это совсем не нужно: просто вызовите' startService' безоговорочно – pskink

+0

Спасибо @pskink. Я не был уверен в этом. Собирался попробовать и посмотреть. –

+0

'startService' docs say:« ... Если эта служба еще не запущена, она будет создана и запущена (создав для нее процесс, если это необходимо), если она запущена, она остается запущенной. ... Обратите внимание, что вызовы startService() не вложенные: независимо от того, сколько раз вы вызываете startService(), один вызов stopService (Intent) остановит его. ..." – pskink

 Смежные вопросы

  • Нет связанных вопросов^_^