2011-12-23 25 views
34

Tôi có một dịch vụ mà bị ràng buộc với bối cảnh ứng dụng như thế này:Android: Làm thế nào để unbind một dịch vụ an toàn

getApplicationContext().bindService(
        new Intent(this, ServiceUI.class), 
        serviceConnection, 
        Context.BIND_AUTO_CREATE 
      ); 

protected void onDestroy() { 
      super.onDestroy();     
      getApplicationContext().unbindService(serviceConnection); 
     } 

Đối với một số lý do, chỉ đôi khi bối cảnh ứng dụng không ràng buộc đúng cách (tôi không thể sửa chữa một phần), tuy nhiên trong onDestroy() tôi làm unbindservice đó ném một lỗi

java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection. 

câu hỏi của tôi là: có cách nào để gọi unbindservice một cách an toàn hoặc kiểm tra xem nó đã được ràng buộc với một dịch vụ trước khi unbinding nó?

Xin cảm ơn trước.

+0

séc http: // stackoverflow.com/questions/1916253/bind-service-to-activity-in-android –

+0

Tôi đã đi qua điều này trước nhưng điều đó không giải quyết vấn đề của tôi, chúng ta hãy chỉ nói rằng tôi gọi UnBindService mà không gọi BindService(), làm thế nào để xử lý lỗi mà không có FC ứng dụng? – 2ndlife

+0

Bạn không thể bắt được ngoại lệ và tiếp tục? – dragonroot

Trả lời

57

Hãy thử điều này:

boolean isBound = false; 
... 
isBound = getApplicationContext().bindService(new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE); 
... 
if (isBound) 
    getApplicationContext().unbindService(serviceConnection); 

Lưu ý:

Bạn nên sử dụng cùng context cho ràng buộc một dịch vụ và unbinding một dịch vụ. Nếu bạn đang ràng buộc Dịch vụ với getApplicationContext(), do đó bạn cũng nên sử dụng getApplicationContext.unbindService(..)

+1

Tôi đã theo dõi câu trả lời của bạn và tôi vẫn gặp lỗi tương tự. @Yury trả lời khắc phục sự cố. – VansFannel

+0

cả hai câu trả lời là chính xác: một từ Andrey Novikov và @Yury – Snicolas

+0

Dường như với tôi giải pháp này sẽ làm rò rỉ dịch vụ bị ràng buộc, bởi vì tôi chỉ tìm ra sự ràng buộc phải được gọi trên cùng một ngữ cảnh. Vì vậy, thử nghiệm trên một bối cảnh khác nhau có thể tạo ra kết quả lẻ có thực sự bị ràng buộc hai lần đến một dịch vụ cụ thể (nếu có thể?) – 3c71

7

Here bạn có thể tìm thấy giải thích và mã nguồn tốt đẹp về cách làm việc với các dịch vụ bị ràng buộc. Trong trường hợp của bạn, bạn nên ghi đè lên các phương thức (onServiceConnectedonServiceDisconnected) của đối tượng ServiceConnection. Sau đó, bạn có thể chỉ cần kiểm tra mBound biến trong mã của bạn.

+0

Tôi sợ ví dụ nhất định là dành cho dịch vụ địa phương, không phải dịch vụ xử lý từ xa. –

+4

Không giống như địa phương, ràng buộc với các dịch vụ từ xa sẽ cung cấp cho chúng ta 'onServiceDisconnected()' gọi lại nếu quá trình của dịch vụ đích chết và 'onServiceConnected()' sẽ được gửi lại khi nó được khởi động lại. Nếu bạn dựa vào những lời gọi đó cho cờ 'mBound', bạn sẽ bị rò rỉ kết nối dịch vụ nếu cố gắng hủy liên kết được thực hiện ở giữa' onServiceDisconnected() 'và' onServiceConnected() 'khi' mBound' sẽ là ' false'. –

+0

Để giải quyết vấn đề này, không đặt mBound thành false trong onServiceDisconnected. Và nếu có nhu cầu theo dõi trạng thái kết nối và ngắt kết nối, có thể giới thiệu một biến mConnected khác. –

4

Làm chính xác những gì Andrey Novikov đã đề xuất không hoạt động đối với tôi. Tôi chỉ đơn giản là thay thế:

getApplicationContext().unbindService(serviceConnection); 

Với:

unbindService(serviceConnection); 
+0

** serviceConnection ** là gì? –

4

tôi thấy có hai vấn đề. Cố gắng liên kết nhiều lần và cũng cố gắng hủy liên kết nhiều lần.

Giải pháp:

public class ServiceConnectionManager implements ServiceConnection { 

    private final Context context; 
    private final Class<? extends Service> service; 
    private boolean attemptingToBind = false; 
    private boolean bound = false; 

    public ServiceConnectionManager(Context context, Class<? extends Service> service) { 
     this.context = context; 
     this.service = service; 
    } 

    public void bindToService() { 
     if (!attemptingToBind) { 
      attemptingToBind = true; 
      context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE); 
     } 
    } 

    @Override 
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 
     attemptingToBind = false; 
     bound = true; 
    } 

    @Override 
    public void onServiceDisconnected(ComponentName componentName) { 
     bound = false; 
    } 

    public void unbindFromService() { 
     attemptingToBind = false; 
     if (bound) { 
      context.unbindService(this); 
      bound = false; 
     } 
    } 

} 
+2

Điều này làm việc, nhưng nó có vẻ thực sự khó xử mà bạn phải duy trì 'ràng buộc' bằng tay - nó có vẻ như nó phải là một biến nội bộ có thể truy cập. –

+0

@DavidDoria Nó có vẻ có vẻ khó xử nhưng nó thực sự là cách Android hiển thị như thế nào để làm điều đó: http://developer.android.com/guide/components/bound-services.html – ForceMagic

+0

Câu trả lời này làm việc cho tôi bởi vì tôi nhận ra rằng tôi đã , ngu ngốc, gọi myService.unbindService (myServiceConnectionManager) thay vì gọi context.unbindService (...) –

0

Không chắc về tất cả các câu trả lời ở trên, nó dường như quá phức tạp trong khi không ai trong số những sẽ phù hợp với những vấn đề tôi đã có.

Chỉ liên kết/hủy liên kết một lần tại một thời điểm và dịch vụ chắc chắn bị ràng buộc tại thời điểm lệnh unbind(). Không muốn rò rỉ bất cứ điều gì, vì vậy tôi chỉ cần chắc chắn rằng tôi đã sử dụng bối cảnh tương tự cho các cuộc gọi bind() và unbind() và giải quyết nó vĩnh viễn! Làm một cái gì đó như thế này:

any_context.getApplicationContext().bind(...); 

... 

another_context.getApplicationContext().unbind(...); 
0

Tôi nghĩ rằng guide là không hoàn toàn đúng như đã đề cập here Surya Wijaya Madjid. Rò rỉ bộ nhớ có thể xảy ra khi dịch vụ bị ràng buộc bị hỏng và chưa được kết nối lại.

Tôi nghĩ rằng phương pháp này là cần thiết:

Service mService; 

private final ServiceConnection mServiceConnection = new ServiceConnection() 
{ 
    boolean bound = false; 

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

    @Override 
    public void onServiceConnected(ComponentName name, IBinder service) 
    { 
     mService = ((MyService.ServiceBinder) service).getService(); 

     if (!bound) 
     { 
      // do some action - service is bound for the first time 
      bound = true; 
     } 
    } 
}; 

@Override 
public void onDestroy() 
{ 
    if (mService != null) 
    { 
     // do some finalization with mService 
    } 

    if (mServiceConnection.bound) 
    { 
     mServiceConnection.bound = false; 
     unbindService(mServiceConnection); 
    } 
    super.onDestroy(); 
} 

public void someMethod() 
{ 
    if (mService != null) 
    { 
     // to test whether Service is available, I have to test mService, not  mServiceConnection.bound 
    } 
} 
Các vấn đề liên quan