2010-03-21 11 views
25

Tôi có một tình huống cụ thể: một dịch vụ được bắt đầu bởi một bộ thu phát sóng bắt đầu một hoạt động. Tôi muốn làm cho nó có thể cho hoạt động này để giao tiếp trở lại dịch vụ. Tôi đã chọn sử dụng AIDL để làm cho nó có thể. Mọi thứ dường như hoạt động tốt ngoại trừ phương pháp bindService() được gọi là trong onCreate() hoạt động. bindService(), trên thực tế, ném một ngoại lệ con trỏ null vì onServiceConnected() không bao giờ được gọi trong khi phương thức của dịch vụ là . Dù sao bindService() trả về đúng sự thật. Dịch vụ rõ ràng là hoạt động vì nó bắt đầu hoạt động. Tôi biết rằng việc gọi một hoạt động từ một dịch vụ có thể nghe lạ, nhưng tiếc là đây là cách duy nhất để nhận dạng giọng nói trong một dịch vụ.onServiceConnected không bao giờ được gọi sau phương thức bindService

Cảm ơn trước

Trả lời

13

Tôi không thể đưa ra vấn đề chính xác trong mô tả của bạn, vì vậy tôi sẽ đoán ở đây!

Làm cách nào để có thể bindService() ném NullPointerException? Cách duy nhất mà điều này có thể (/ nên) xảy ra là khi bạn không cung cấp Service hoặc một người nghe ServiceConnection.

bindService() không thể ném NullPointerExceptiononServiceConnected() không được gọi. Cuộc gọi đến onServiceConnected() là một sản phẩm của bindService().

Vì vậy, tôi đoán bạn đang gọi phương thức AIDL, trước khi Service thực sự đã được liên kết?

+1

có lỗi, tôi hiểu vấn đề có thể được giải thích tốt hơn. NullPointerException được ném bởi vì giao diện từ xa không bao giờ được điền như remote = IRemoteService.Stub.asInterface (service); trong onServiceConnected() không bao giờ được gọi. BindService có nên kích hoạt onServiceConnected ngay lập tức không? – Matroska

+2

'onServiceConnected()' không nên được gọi là __immediately__, có thể sẽ có một sự chậm trễ nhỏ. – MrSnowflake

+0

Bạn đã đúng! Phương thức này không được gọi ngay lập tức. Đó là vấn đề của tôi. – Matroska

36

Sau giờ và giờ cố gắng tìm ra điều này, vấn đề là các ví dụ cho thấy việc tạo dịch vụ, không bao gồm phương thức onBind hoặc chúng có mã mẫu sau hoặc tạo mã này cho bạn:

public IBinder onBind(Intent intent) { 
    // TODO Auto-generated method stub 
    return null; 
} 

Điều này khiến phương thức onServiceConnected thất bại hoặc không bao giờ thực thi. Việc sửa chữa là rất đơn giản, đó là những điều sau:

public IBinder onBind(Intent intent) { 
    return mBinder; 
} 

Nơi bạn có thể tạo ra một chất kết dính đơn giản như sau để trở lại:

private final IBinder mBinder = new LocalBinder(); 
public class LocalBinder extends Binder { 
    public ConferenceService getService() { 
    return ConferenceService.this; 
    } 
} 
+3

Cảm ơn, Brad, đã cứu tôi một thời gian ở đây! Tôi đã có hai vấn đề, một trong những bạn chỉ ra ở đây cũng như không có dịch vụ được định nghĩa trong tệp kê khai. Tôi thấy rằng kiểm tra trạng thái của bindService() cũng quan trọng. – DustinB

+0

cảm ơn Brad, cũng tiết kiệm cho tôi rất nhiều thời gian – Houcheng

+0

Đây là tài liệu ở đây: http://developer.android.com/guide/components/bound-services.html#Binder – Rolf

37

Tôi vừa trải qua một phiên bản khác của vấn đề này, với cùng một triệu chứng của onServiceConnected(...) không được gọi. Nguyên nhân là khác nhau trong trường hợp của tôi.

Bạn phải đảm bảo khai báo dịch vụ trong tệp AndroidManifest.xml trong thẻ ứng dụng - đây là gốc của sự cố đối với tôi.

<application android:name=".YourAppTitle" android:icon="@drawable/icon" android:label="@string/app_name"> 
    <activity android:name=".Main" android:label="@string/app_name"> 
    </activity> 
    <service android:name="YourService" /> 
</application> 

Có một biến chứng thêm nếu bạn đang sử dụng một thư viện Android riêng biệt trong Eclipse - thêm thẻ Dịch vụ này dường như chỉ để sửa chữa vấn đề này nếu dịch vụ tham chiếu là trong gói giống như biểu hiện; tức là nếu ứng dụng của bạn nằm trong gói a.b.c và đây là nơi AndroidManifest.xml cư trú, thì 'YourService' cũng phải nằm trong gói a.b.c. (được sao chép thủ công từ thư viện khác, nếu cần) hoặc nếu không, thẻ <service..> có thể/sẽ bị bỏ qua và onServiceConnected(...) sẽ không được gọi.

Đây là trường hợp của dự án của tôi mặc dù tôi đã sử dụng tuyên bố nhập phù hợp cho Dịch vụ trong mã của tôi.Eclipse không có lỗi, do đó, việc nhập khẩu đã xác định chính xác lớp từ một thư viện khác trong vùng làm việc Eclipse.

HTH

+0

Dịch vụ của tôi nằm trong thư viện và tôi gặp sự cố này — bạn có phải tạo một dịch vụ mới kế thừa dịch vụ cũ không? –

+0

Tôi đã có một dự án thư viện có chứa một dịch vụ thanh toán mà tôi muốn giữ phần lớn giống hệt nhau trong một loạt các dự án con; Tôi đã sửa đổi điều này để được trừu tượng và thực hiện một dịch vụ kế thừa nó trong dự án phụ, nhưng tôi nhận được lỗi tương tự như trước đây. Để rõ ràng, lệnh gọi 'bindService (...)' có phải đến từ 'Dịch vụ' kế thừa hay nó có thể nằm trong phần tử trừu tượng không? Và bạn có biết nguyên nhân gốc rễ của vấn đề này không? –

+0

Điều tôi viết là tất cả những thông tin tôi có; Tôi đã ngừng phát triển Android thông qua sự thất vọng với lỗi API và chương trình cơ sở kể từ khi đăng bài năm ngoái. – KomodoDave

8

Một điều nữa là nếu bạn đang gọi bindservice phương pháp bên trong oncreate phương pháp thì onserviceconnected được gọi sau khi phương pháp oncreate kết thúc.

Vì vậy, mọi tham chiếu đến chức năng giao diện trước khi kết thúc oncreate (hoặc trước onserviceconnected được gọi) hiển thị ngoại lệ con trỏ null.

+0

Đây chính xác là vấn đề tôi đang gặp phải, tôi đã gọi đến liên kết (... trong onCreate và không biết tại sao dịch vụ luôn trả về null, cảm ơn bạn !! – Sauron

+0

Điều này đã khắc phục sự cố cho tôi, cảm ơn –

22

Sự kiện onServiceConnected không bao giờ được gọi trong ứng dụng của tôi.

Vấn đề là tôi đã có tên dịch vụ quy định tại Application tôi Manifest như:

<service android:name="MyService" android:enabled="true"></service> 

Khi tôi thay đổi nó để tên lớp đầy đủ nó làm việc:

<service android:name="com.example.MyService" android:enabled="true"></service> 

Cập nhật: Bạn cũng có thể sử dụng tên lớp tương đối:

<service android:name=".MyService" android:enabled="true"></service> 

Chỉ định tên lớp bằng cách sử dụng đầy đủ com.example.MyServiceClass thay vì chỉ MyServiceClass.

+0

Cảm ơn Trong trường hợp của tôi sử dụng "MyService" là đủ, nhưng với sự điên rồ của lập trình trong Java, tôi đoán đây có thể là tùy chọn an toàn hơn (hoặc an toàn nhất) bất cứ khi nào tôi triển khai dịch vụ. –

+3

thực sự bạn cần phải đặt trong ".MyService" không phải là đầy đủ, trừ khi nó ở bên ngoài gói –

+1

Tôi không chính xác hiểu tại sao nhưng điều này là hoàn toàn đúng! Câu trả lời này chỉ cố định vấn đề của tôi. – codepushr

4

Tuy nhiên, một nguyên nhân khác đối với câu hỏi ban đầu có thể là dịch vụ chưa chạy và bạn đang chuyển 0 làm cờ thành bindService. Cũng giống như vậy:

bindService(intent, serviceConnection, 0); 

Khi những gì bạn đang tìm kiếm sẽ là:

bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); 
1

Có thể có một lời giải thích, không phải là một tình huống rất thường xuyên, nhưng tôi quản lý để có được vào nó và mất 2 giờ để giải quyết nó.

Vì vậy, những gì tôi đã làm là tôi muốn sử dụng lại gói từ ý định nhận được bằng phương pháp onBind. Nhưng tôi đã đi cho phiên bản lười biếng và thay đổi lớp học của ý định. Rõ ràng điều này khiến cho onServiceConnected không được gọi. Có lẽ vì hệ thống giữ một tham chiếu đến mục đích và sử dụng nó khi gọi onServiceConnected.

Kết luận không thay đổi ý định bạn nhận được trong onBind.

0

Tôi đã gọi đến liên kết bằng Intent trống - getContext().bindService(new Intent(), mConnection, Context.BIND_AUTO_CREATE). Tôi phải làm cho mục đích cụ thể hơn để chỉ ra dịch vụ nào tôi muốn liên kết. Điều này rõ ràng là một lỗi mã, nhưng đầu ra Logcat là tiếc là không đủ rõ ràng.