2012-12-06 23 views
9

Tôi đã viết hai ứng dụng (nhắm mục tiêu Gingerbread). Giả sử app1 và app2. App1 có hai dịch vụ bắt đầu bằng "BOOT_COMPLETED" và chúng được bắt đầu với giá trị trả về START_STICKY. Chúng chạy trong các luồng riêng biệt. Để viết một câu chuyện dài. Một trong những dịch vụ được xem cho dữ liệu đến trên một cổng nối tiếp (một loại proxy cho ứng dụng giao tiếp với các giao diện ở đầu kia của cổng nối tiếp). Người kia có người nghe xem một số trạng thái hệ thống và chờ một số "hướng dẫn" từ các ứng dụng khác. Tôi biết họ đang chạy tốt bởi vì họ được liệt kê trong các dịch vụ đang chạy và tôi đã thêm một số mã buộc họ phải làm một số công cụ khi một số dữ liệu cụ thể đến từ cổng nối tiếp.Ràng buộc với một dịch vụ từ một ứng dụng khác

Bây giờ vấn đề: Tôi đã viết app2. Nó cố gắng liên kết với một trong các dịch vụ trong app1. Tôi đã sử dụng tài liệu android-developper và triển khai giao tiếp hai chiều giữa dịch vụ trong app1 và app2. Vì tôi chỉ có một lượng nhỏ dữ liệu rất đơn giản để gửi, tôi đã sử dụng một sứ giả, như đã đề xuất. Tôi về cơ bản chỉ sử dụng "cái gì, arg1 và arg2" Tôi không sử dụng giao diện AIDL như tài liệu đã được đề xuất.

Đây là phần của androidmanifest khai báo dịch vụ trong app1 Tôi cũng cố gắng ràng buộc.

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

Sau đó, đây là một vài phương pháp đối phó với vấn đề này trong app1:

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

Đối app2, đây là mã có liên quan đến thiết lập các ràng buộc với các thông tin liên lạc hai chiều:

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

Nhìn vào các dịch vụ đang chạy, tôi có thể thấy rằng dịch vụ tôi đã tạo trong app2 đang chạy. Logcat cho tôi thấy rằng tôi cố gắng ràng buộc ModemWatcherService nhưng không tìm thấy nó. Dưới đây là phần thú vị của 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 

Suy nghĩ đầu tiên của tôi là tôi đã mất tích một phép nhưng bindService() có thể TROW ngoại lệ an ninh và trong trường hợp này nó không như vậy, tôi đã kiểm tra và nó trả về false cho một lý do không rõ. Ngoài ra, tôi biết rằng trong app1, onBind không bao giờ được gọi là chứng minh rằng ràng buộc không bao giờ xảy ra. Vì vậy, các thông điệp logcat "không tìm thấy" có ý nghĩa nhưng tôi tuyên bố rằng dịch vụ công khai trong biểu hiện của nó. Nó có thể là một sai lầm đơn giản nhưng tôi đã được phát hành này trong một thời bây giờ và tôi đã không tìm thấy lý do tại sao. Bất kỳ ý tưởng tại sao app2 không thể tìm thấy dịch vụ trong app1? Tôi đã sử dụng chỉ cần cắt và dán cho tên vì vậy tôi sẽ không làm sai lầm sai lầm ngu ngốc trong tên. Tôi có thiếu quyền hạn của một số loại? Tôi có cần thực hiện thêm một số bước để xuất bản dịch vụ cho toàn bộ hệ thống không? Đó là lần đầu tiên tôi cố gắng truy cập nội dung nào đó trong một ứng dụng từ một ứng dụng khác, vì vậy, tôi có thể đã bỏ lỡ điều gì đó.

Trả lời

15

ComponentName của bạn được xây dựng không chính xác. Khi đi qua trong tên lớp là phải có đủ điều kiện đầy đủ như sau:

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

Một điều, nếu bạn đang tham khảo một Service bên ngoài ranh giới của các ứng dụng, nó có lẽ là tốt nhất không nên sử dụng ComponentName để tham khảo nó, ngay cả khi nó hoạt động chính xác. Một cách tiếp cận phổ biến hơn là tạo chuỗi ACTION tùy chỉnh cho Intent của bạn và có bộ lọc Service hành động đó.

+1

Cảm ơn nó hoạt động. Đó là vấn đề. Và cảm ơn cho các thực hành tốt hơn lưu ý quá. –

+3

Vì kẹo que bị cấm liên kết với dịch vụ sử dụng ý định ngầm. Vì vậy, ComponentName có vẻ là lựa chọn duy nhất. – Ov3r1oad

Các vấn đề liên quan