2012-12-06 25 views
9

İki uygulama yazdım (hedef Gingerbread). App1 ve app2 diyelim. App1, "BOOT_COMPLETED" ile başlatılan iki hizmete sahiptir ve START_STICKY dönüş değeriyle başlamaktadır. Ayrı dişlerde çalışırlar. Uzun lafın kısası. Hizmetlerden biri, seri bağlantı noktasında (seri bağlantı noktasının diğer ucundaki arabirimlerle iletişim kuran uygulama için bir çeşit proxy) gelen verileri izliyor. Diğerinde ise, bazı sistem durumunu izleyen ve diğer uygulamalardan bazı "talimatlar" bekleyen bir dinleyici var. İyi çalıştığını biliyorum çünkü bunlar çalışan hizmetlerde listeleniyor ve bazı özel verileri seri bağlantı noktasından geldiğinde bazı şeyleri yapmaya zorlayan bir kod ekledim.Başka bir uygulamadan bir hizmete bağlanma

Şimdi sorun: app2 yazdım. App1'deki hizmetlerden birine bağlanmaya çalışır. android-developper belgelerini kullandım ve app1 ve app2'deki hizmet arasında iki yönlü bir iletişim gerçekleştirdim. Göndermek için az miktarda çok basit veriye sahip olduğumdan, önerildiği gibi bir haberci kullandım. Temel olarak sadece "what, arg1 ve arg2" yi kullanarak, belgenin önerdiği gibi AIDL arayüzünü kullanmadım.

App1'de hizmeti bildiren androidmanifest bölümü de ben de bağlanmayı deniyorum.

public final class ComWithIoMcu extends Service { 
private static final String TAG = "ComWithIoMcu"; 
/** Messenger for communicating with service. */ 
static Messenger mServiceMcu = null; 
/** Flag indicating whether we have called bind on the service. */ 
boolean mIsBound; 

/** 
* Command to the service to register a client, receiving callbacks 
* from the service. The Message's replyTo field must be a Messenger of 
* the client where callbacks should be sent. 
*/ 
static final int MSG_REGISTER_CLIENT = 1; 

/** 
* Command to the service to unregister a client, ot stop receiving callbacks 
* from the service. The Message's replyTo field must be a Messenger of 
* the client as previously given with MSG_REGISTER_CLIENT. 
*/ 
static final int MSG_UNREGISTER_CLIENT = 2; 
/** 
* Command to forward a string command to the I/O MCU 
*/  
public static final int MSG_SEND_STRING_TO_IOMCU = 3; 
/** List of supported commands 
* 
*/ 
    ...... more code .... 

/** 
* Handler of incoming messages from service. 
*/ 
class IncomingHandler extends Handler { 
    @Override 
    public void handleMessage(Message msg) { 
     switch (msg.what) { 
      case MSG_UNSOL_MESSAGE: 
       Log.d(TAG, "Received from service: " + msg.arg1); 
       break; 
      default: 
       super.handleMessage(msg); 
     } 
    } 
} 

/** 
* Target we publish for clients to send messages to IncomingHandler. 
*/ 
final Messenger mMessenger = new Messenger(new IncomingHandler()); 
boolean mBound; 

/** 
* Class for interacting with the main interface of the service. 
*/ 
private ServiceConnection mConnection = new ServiceConnection() { 
    public void onServiceConnected(ComponentName className, 
      IBinder service) { 
     // This is called when the connection with the service has been 
     // established, giving us the service object we can use to 
     // interact with the service. We are communicating with our 
     // service through an IDL interface, so get a client-side 
     // representation of that from the raw service object. 
     mServiceMcu = new Messenger(service); 
     Log.d(TAG, "Attached."); 

     // We want to monitor the service for as long as we are 
     // connected to it. 
     try { 
      Message msg = Message.obtain(null, 
        MSG_REGISTER_CLIENT); 
      msg.replyTo = mMessenger; 
      mServiceMcu.send(msg); 

     } catch (RemoteException e) { 
      // In this case the service has crashed before we could even 
      // do anything with it; we can count on soon being 
      // disconnected (and then reconnected if it can be restarted) 
      // so there is no need to do anything here. 
      Log.e(TAG, "ModemWatcherService is not running"); 
     } 
    } 

    public void onServiceDisconnected(ComponentName className) { 
     // This is called when the connection with the service has been 
     // unexpectedly disconnected -- that is, its process crashed. 
     mServiceMcu = null; 
     mBound = false; 


    } 
}; 

void doBindService() { 
    // Establish a connection with the service. We use an explicit 
    // class name because there is no reason to be able to let other 
    // applications replace our component. 
    //bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); 
    try { 
     Intent intentForMcuService = new Intent(); 
     Log.d(TAG, "Before init intent.componentName"); 
     intentForMcuService.setComponent(new ComponentName("com.admetric.modemwatcher", "ModemWatcherService")); 
     Log.d(TAG, "Before bindService"); 
     if (bindService(intentForMcuService, mConnection, 0)){ 
      Log.d(TAG, "Binding to Modem Watcher returned true"); 
     } else { 
      Log.d(TAG, "Binding to Modem Watcher returned false"); 
     } 
    } catch (SecurityException e) { 
     Log.e(TAG, "can't bind to ModemWatcherService, check permission in Manifest"); 
    } 
    mIsBound = true; 
    Log.d(TAG, "Binding."); 
} 

void doUnbindService() { 
    if (mIsBound) { 
     // If we have received the service, and hence registered with 
     // it, then now is the time to unregister. 
     if (mServiceMcu != null) { 
      try { 
       Message msg = Message.obtain(null, MSG_UNREGISTER_CLIENT); 
       msg.replyTo = mMessenger; 
       mServiceMcu.send(msg); 
      } catch (RemoteException e) { 
       // There is nothing special we need to do if the service 
       // has crashed. 
      } 
     } 

     // Detach our existing connection. 
     unbindService(mConnection); 
     mIsBound = false; 
     Log.d(TAG, "Unbinding."); 
    } 
} 
:

Uyg2 için
@Override 
public IBinder onBind(Intent intent) { 
    Log.d(TAG, "entering onBind"); 
    return mMessenger.getBinder(); 
} 

/** 
* Handler of incoming messages from clients. 
*/ 
class IncomingHandler extends Handler { 
    @Override 
    public void handleMessage(Message msg) { 
     String logMessage = "Received meaasge what= %d, arg1= %d, arg2= %d" + String.valueOf(msg.what) + String.valueOf(msg.arg1) + String.valueOf(msg.arg2); 
     Log.d(TAG, logMessage); 
     switch (msg.what) { 
      case MSG_REGISTER_CLIENT: 
       mClients.add(msg.replyTo); 
       break; 
      case MSG_UNREGISTER_CLIENT: 
       mClients.remove(msg.replyTo); 
       break; 
      case ..... 
      more code here for the application 
      default: 
       super.handleMessage(msg); 
     } 
    } 
} 


@Override 
public void onCreate() { 
    mHandler = new Handler(); 
    startSignalLevelListener(); 
    Log.i(TAG, "Just did onCreated"); 
    // Display a notification about us starting. We put an icon in the status bar. 
    // showNotification(); 
} 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
    Log.i(TAG, "Received start id " + startId + ": " + intent); 
    // We want this service to continue running until it is explicitly 
    // stopped, so return sticky. 
    return START_STICKY; 
} 

, burada çift yönlü iletişim ile bağlama kurmak için ilgili koddur: Sonra

<service android:name=".ModemWatcherService" 
       android:label="@string/app_name" 
       android:exported="true"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
      <!-- Service name --> 
      <action android:name="com.admetric.modemwatcher.Service" /> 
     </intent-filter> 
    </service> 

, burada Uyg1 içinde bu konu ile ilgili birkaç yöntem vardır

Çalışan hizmetlere baktığımda, app2 uygulamasında oluşturduğum hizmetin çalıştığını görebiliyorum. Logcat, ModemWatcherService'i bağlamayı denediğimi gösteriyor ancak bulunmuyor. İşte LogCat ilginç bölümüdür

12-05 17:22:59.884 D/ComWithIoMcu( 547): Before init intent.componentName 
12-05 17:22:59.884 D/ComWithIoMcu( 547): Before bindService 
12-05 17:22:59.888 D/ComWithIoMcu( 547): Binding to Modem Watcher returned false 
12-05 17:22:59.888 D/ComWithIoMcu( 547): Binding. 
12-05 17:22:59.888 W/ActivityManager( 89): Unable to start service Intent { cmp=com.admetric.modemwatcher/ModemWatcherService }: not found 

Aklıma ilk izni eksikti ama bindService() güvenlik istisnaları trow olabilir ve bu durumda o kadar, kontrol ettim yok ve bir için false döndüren oldu bilinmeyen sebep. Ayrıca, app1'de, onBind'in asla bağlanmanın hiçbir zaman gerçekleşmediğini kanıtlamadığını da biliyorum. Bu nedenle "bulunamadı" logcat mesajı anlamlıdır ancak bu hizmeti kamuya açık olarak beyan ettim. Muhtemelen basit bir hatadır ama bu süredir bir süredir yayınlandım ve nedenini bulamadım. App2'nin uygulama1'de bu hizmeti neden bulamadığı konusunda bir fikriniz var mı? Sadece isimleri kesip yapıştırdım, bu yüzden isimlerde aptalca yanlış yazım hataları yapmam. Bazı tür izinleri kaçırıyor muyum? Tüm sistem için hizmeti yayınlamak için fazladan bir adım atmam gerekiyor mu? Bu, bir uygulamada başka bir uygulamadan bir şeye ilk kez erişmeyi denediğimde, bir şeyleri kaçırmış olabilirim.

cevap

15

ComponentName'unuz yanlış yapılandırılmıştır. sınıf adı iletilirken tamamen şöyle kalifiye olmalıdır edilir:

intentForMcuService.setComponent(new ComponentName("com.admetric.modemwatcher", 
     "com.admetric.modemwatcher.ModemWatcherService")); 

Başka bir şey, uygulamanın sınırları dışında bir Service başvuran, eğer var muhtemelen en iyi referans olarak kullanmak için ComponentName kullanmamayı, bile doğru çalışıyor. Daha yaygın bir yaklaşım, Intent için özel bir ACTION dize oluşturmak ve bu eylemi Service filtresine sahip olmaktır.

+1

Teşekkürler çalışıyor. Sorun buydu. Ve daha iyi uygulama notu için de teşekkürler. –

+3

Lolipop'tan bu yana örtük niyetle hizmete bağlanmak yasak. Yani ComponentName tek seçenek gibi görünüyor. – Ov3r1oad

İlgili konular