2017-01-02 2 views
0

Я хотел получить некоторый опыт использования android IPC с помощью AIDL. Я хотел посмотреть, можно ли общаться между двумя отдельными приложениями для Android.bindService() в клиентском приложении терпит неудачу при попытке сделать IPC с другим приложением

Моя проблема заключается в том, что при вызове bindService во втором приложении для связи с первым приложением FactorialService служба всегда терпит неудачу. Моя первая активность приложения MainActivity, которая пытается позвонить bindService, всегда регистрирует тот факт, что bindService возвращает false. Плюс MainActivity (который реализует ServiceConnection) этого второго приложения (клиентское приложение) никогда не получает вызываемый метод обратного вызова onServiceConnected.

Так, в первого приложения который проходит службу под названием FactorialService

  • Я определил
    интерфейс, IFactorialService.aidl:

    package com.simonlbc.factorialcommon; 
    
    import com.simonlbc.factorialcommon.FactorialRequest; 
    import com.simonlbc.factorialcommon.FactorialResponse; 
    
    interface IFactorialService { 
        FactorialResponse fact(in FactorialRequest r); 
    } 
    

FactorialRequest содержит номер входа (n). fact возвращает n! вместе с другой информацией.

  • В одном приложении я создал класс IFactorialServiceImplem реализующий что aidl интерфейс.

    package com.example.simonlbc.factorialservice; 
    import android.app.Service; 
    import android.content.Intent; 
    import android.os.IBinder; 
    import android.os.SystemClock; 
    import com.simonlbc.factorialcommon.FactorialResponse; 
    import com.simonlbc.factorialcommon.FactorialRequest; 
    
    public class IFactorialServiceImplem extends com.simonlbc.factorialcommon.IFactorialService.Stub { 
    
        public long recursiveFact(int n) { 
         if (n < 0) 
          throw new IllegalArgumentException("input fa"); 
         if (n == 1 || n == 0) 
          return 1; 
         else { 
          return n * recursiveFact(n-1); 
         } 
        } 
    
        public long iterativeFact(int n) { 
         long res = 1; 
         for (int i = 1; i <= n; i++) 
          res *= i; 
         return res; 
        } 
        public FactorialResponse fact(FactorialRequest r) { 
         long timeInMillis = SystemClock.uptimeMillis(); 
         long result = 0; 
    
         switch(r.getChoice()) { 
          case RECURSIVE: 
           result = recursiveFact(r.getInNb()); 
           break; 
          case ITERATIVE: 
           result = iterativeFact(r.getInNb()); 
         } 
         timeInMillis = SystemClock.uptimeMillis() - timeInMillis; 
    
         return new FactorialResponse(result, timeInMillis); 
        } 
    } 
    
    • Затем я создал Service, который будет использоваться для связи с IFactorialService экземпляра возможных клиентов:

      package com.example.simonlbc.factorialservice; 
      import android.app.Service; 
      import android.content.Intent; 
      import android.os.IBinder; 
      import android.util.Log; 
      import com.simonlbc.factorialcommon.IFactorialService; 
      
      public class FactorialService extends Service { 
      
          private IFactorialServiceImplem s = null; 
          private static final String TAG = "FactorialService"; 
      
          @Override 
          public void onCreate() { 
           super.onCreate(); 
           s = new IFactorialServiceImplem(); 
           Log.d(TAG, "onCreate'd"); 
          } 
           @Override 
           public IBinder onBind(Intent intent) { 
            Log.d(TAG, "onBind()'d"); 
            return this.s; 
           } 
      
           @Override 
           public boolean onUnbind(Intent intent) { 
            Log.d(TAG, "onUnbind()'d"); 
            return super.onUnbind(intent); 
           } 
      
           @Override 
           public void onDestroy() { 
            Log.d(TAG, "onDestroy()'d"); 
            s = null; 
            super.onDestroy(); 
           } 
          } 
      
      • манифест этой первой «сервис» приложение является следующее:

      <application 
          android:allowBackup="true" 
          android:icon="@mipmap/ic_launcher" 
          android:label="@string/app_name" 
          android:supportsRtl="true" 
          android:theme="@style/AppTheme"> 
      
          <service 
           android:name=".FactorialService"> 
           <!-- 
           android:enabled="true" 
           android:exported="true" 
           android:process=":remote" 
           --> 
      
           <intent-filter> 
            <action android:name="com.example.simonlbc.factorialservice.FactorialService" /> 
           </intent-filter> 
          </service> 
      
          <activity android:name=".MainActivity"> 
           <intent-filter> 
            <action android:name="android.intent.action.MAIN" /> 
      
            <category android:name="android.intent.category.LAUNCHER" /> 
           </intent-filter> 
          </activity> 
      </application> 
      

    • первое приложение содержит деятельность Launcher, который просто запускает услугу, как так:

      @Override 
          protected void onCreate(Bundle savedInstanceState) { 
           super.onCreate(savedInstanceState); 
           setContentView(R.layout.activity_service); 
           curPackage = getString(R.string.packageService); 
           MainActivity.this.startService(
             new Intent() 
               .setAction(curPackage + ".FactorialService") 
               .setPackage(curPackage) 
           ); 
          } 
      


  • Мой второй пусковой активности приложений «ы такой как:

    public class MainActivity extends Activity implements View.OnClickListener, ServiceConnection

    Я хочу MainActivity этого второго приложения к
    общаться с первым приложением IFactorialService-х. В onResume я пытаются связать с обслуживанием первого приложения:

    @Override 
        protected void onResume() { 
         super.onResume(); 
         Intent i = new Intent(); 
         i.setAction("com.example.simonlbc.factorialservice.FactorialService"); 
         i.setPackage("com.example.simonlbc"); 
         if (!super.bindService(i, this, BIND_AUTO_CREATE)) 
          Log.w(TAG, "Failed to bind our service!!!"); 
        } 
    

Но, похоже bindService терпит неудачу. Действительно каждый раз, когда я приостанавливаю приложение и возвращаюсь к нему, или начинаю его. «Не удалось связать наш сервис !!!» отображается.

Обратите внимание, что два приложения совместно используют модуль библиотеки Android, содержащий определения необходимых файлов помощи.

Вы видите что-нибудь, что позволило бы bindService() работать?

ответ

1

Почему вы используете super.bindservice()? Вместо этого, вы можете попробовать это getApplicationContext().bindservice()

Кроме того, если это не работает, либо, попробуйте следующую модификацию кода:

Intent i = new Intent("com.example.simonlbc.factorialservice.FactorialService"); 
    if(getApplicationContext().startService(i) != null){ 
     if (!getApplicationContext().bindService(i, serviceConnection, 0)) 
      Log.w(TAG, "Failed to bind our service!!!"); 
    } 

где seriveConnection является объект подключения услуг (я предпочитаю не использовать this для ServiceConnection). Кроме того, ваш сервис должен иметь соответствующий набор Action, в противном случае он не запустится

+0

Спасибо, положил 'this' или' getApplicationContext'. Мне все еще нужен i.setPackage («com.example.simonlbc.factorialService»), иначе я бы получил это RuntimeError: «Назначение службы должно быть явным». В этот момент я тоже сделал опечатку! Вместо 'com.example.simonlbc.factorialService' я написал' com.example.simonlbc' в 'i.setPackage'.Это указывает на родительский пакет службы в первом приложении, а не на точный пакет службы в первом приложении. – Simonlbc

+0

Также кажется, что добавление 'if (getApplicationContext(). StartService (i)! = Null) {' необходимо только. У меня нет двух приложений, работающих одновременно. Но очень приятно видеть, что если я не запускаю приложение «Сервис», приложение «Клиент», похоже, сможет запустить службу! И если оба приложения работают одновременно, клиентское приложение может общаться с уже запущенной службой в приложении «Сервис». – Simonlbc

+0

Еще одно примечание для меня или других, возможно, других людей. Я не решался помещать следующие теги в манифест приложения Service рядом с : 'android: enabled =" true " android: exported =" true " android: process =": ​​remote "' 'exported' уже defaulted to true, что делает услугу полезной извне приложения. 'android: process =": ​​remote "' из [doc] (https://developer.android.com/guide/topics/manifest/service-element.html) бесполезен для меня (я думал, что это говорит о том, что сервис был полезен вне приложения, это не так). По умолчанию значение 'enabled' равно true. – Simonlbc

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