2012-12-06 18 views
9

私は2つのアプリ(ターゲットジンジャーブレッド)を書きました。たとえば、app1とapp2としましょう。 App1には「BOOT_COMPLETED」で開始された2つのサービスがあり、それらは戻り値START_STICKYで開始されます。それらは別々のスレッドで実行されます。長い話を短くします。サービスの1つは、シリアルポート(シリアルポートの反対側にあるインターフェイスと通信するアプリケーション用のプロキシの一種)で受信データを監視しています。もう1人は、システムステータスを見て、他のアプリからの「指示」を待っているリスナーを持っています。実行中のサービスに列挙されているため、実行中であることが分かりました。シリアルポートから特定のデータが来たときに何らかの処理を実行するようなコードを追加しました。別のアプリからのサービスへのバインド

問題:私はapp2を書いた。 app1のサービスの1つにバインドしようとします。 android-developperのドキュメントを使用し、app1とapp2のサービス間で双方向通信を実装しました。私は送信する非常に単純なデータがほんの少ししかないので、私はメッセンジャーを使用しました。私は基本的に "what、arg1 and arg2"を使用しています。ドキュメンテーションが示唆しているように、私はAIDLインターフェイスを使用しませんでした。

ここでは、app1のサービスを宣言するandroidmanifestのセクションです。私もバインドしようとしています。ここ

<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> 

その後は、APP1でこの問題に対処するいくつかの方法があります:APP2については

@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; 
} 

、ここでの双方向通信との結合を確立するために、関連するコードは次のとおりです。

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."); 
    } 
} 

実行中のサービスを見ると、app2で作成したサービスが実行中であることがわかります。 Logcatは、私がModemWatcherServiceをバインドしようとしているが、見つからないことを示しています。ここでlogcatの興味深い部分はある

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 

私の最初の考えは、私は許可がありませんでしたが、bindService()はセキュリティ例外をトロウことができ、この場合には、それはそう、私がチェックしないと、それがためにfalseを返すということでした未知の理由。また、私は、app1では、onBindはバインディングが決して起こらなかったことを証明することは決してないことを知っています。したがって、logcatメッセージ "not found"は意味をなさないが、私はそのマニフェストでそのサービスを公開していると宣言した。それはおそらく簡単な間違いですが、私はこのissuでしばらくの間行ってきました。なぜ私はそれを見つけませんでした。 app2でapp1でサービスが見つからない理由は何ですか?私はちょうどカットと名前のために貼り付けたので、私は愚かなミスタイプのミスをしません。私はある種のパーミッションがないのですか?システム全体のサービスを公開するには、いくつかの追加ステップが必要ですか?それは私が別のアプリからあるアプリで何かにアクセスしようとする最初のことなので、私は何かを見逃したかもしれません。

答えて

15

ComponentNameが正しく構成されていません。クラス名にされて渡すときはそうのような完全修飾である必要があります。

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

もう一つは、あなたがアプリケーションの境界の外Serviceを参照している場合、それはあっても、それを参照するためにComponentNameを使用するのではないでしょう最善です正しく動作します。より一般的なアプローチは、あなたのIntentのカスタムACTION文字列を作成し、そのアクションをServiceでフィルタリングすることです。

+1

ありがとうございます。それが問題でした。そして、より良い練習ノートにも感謝します。 –

+3

ロリポップなので、暗黙のインテントを使ってサービスにバインドすることは禁じられています。したがって、ComponentNameは唯一の選択肢のようです。 – Ov3r1oad

関連する問題