Tôi đã kết thúc với một cái gì đó như thế này:
1) để cung cấp cho công cụ phụ trợ một số phạm vi, tôi đã tạo một lớp nội bộ. Ít nhất, nội bộ xấu xí được tách ra khỏi phần còn lại của mã. Tôi cần một dịch vụ từ xa làm một cái gì đó , do đó từ Something
trong tên lớp
private RemoteSomethingHelper mRemoteSomethingHelper = new RemoteSomethingHelper();
class RemoteSomethingHelper {
//...
}
2) có hai điều cần thiết để gọi một phương thức dịch vụ từ xa: các IBinder và mã để thực thi. Vì chúng ta không biết cái nào trở nên nổi tiếng đầu tiên, chúng tôi lưu trữ chúng:
private ISomethingService mISomethingService;
private Runnable mActionRunnable;
Mỗi lần chúng tôi viết thư cho một trong những fileds, chúng tôi gọi _startActionIfPossible()
:
private void _startActionIfPossible() {
if (mActionRunnable != null && mISomethingService != null) {
mActionRunnable.run();
mActionRunnable = null;
}
}
private void performAction(Runnable r) {
mActionRunnable = r;
_startActionIfPossible();
}
này, tất nhiên, giả định Runnable có quyền truy cập vào mISomethingService, nhưng điều này đúng với các runnables được tạo trong các phương thức của lớp RemoteSomethingHelper
.
Thực sự tốt khi gọi lại ServiceConnection
gọi lại are called on the UI thread: nếu chúng tôi định gọi các phương thức dịch vụ từ chuỗi chính, chúng tôi không cần phải quan tâm đến đồng bộ hóa.
ISomethingService
, tất nhiên, được xác định qua AIDL.
3) Thay vì chỉ đi qua đối số cho phương pháp này, chúng ta tạo ra một Runnable rằng sẽ gọi phương pháp này với những lập luận sau, khi gọi có thể:
private boolean mServiceBound;
void startSomething(final String arg1) {
// ... starting the service ...
final String arg2 = ...;
performAction(new Runnable() {
@Override
public void run() {
try {
// arg1 and arg2 must be final!
mISomethingService.startSomething(arg1, arg2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
4) Cuối cùng, chúng tôi nhận được:
private RemoteSomethingHelper mRemoteSomethingHelper = new RemoteSomethingHelper();
class RemoteSomethingHelper {
private ISomethingService mISomethingService;
private Runnable mActionRunnable;
private boolean mServiceBound;
private void _startActionIfPossible() {
if (mActionRunnable != null && mISomethingService != null) {
mActionRunnable.run();
mActionRunnable = null;
}
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
// the methods on this class are called from the main thread of your process.
@Override
public void onServiceDisconnected(ComponentName name) {
mISomethingService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mISomethingService = ISomethingService.Stub.asInterface(service);
_startActionIfPossible();
}
}
private void performAction(Runnable r) {
mActionRunnable = r;
_startActionIfPossible();
}
public void startSomething(final String arg1) {
Intent intent = new Intent(context.getApplicationContext(),SomethingService.class);
if (!mServiceBound) {
mServiceBound = context.getApplicationContext().bindService(intent, mServiceConnection, 0);
}
ComponentName cn = context.getApplicationContext().startService(intent);
final String arg2 = ...;
performAction(new Runnable() {
@Override
public void run() {
try {
mISomethingService.startSomething(arg1, arg2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
}
context
là một trường trong lớp học của tôi; trong một Hoạt động, bạn có thể xác định nó là Context context=this;
Tôi không cần phải xếp hàng; nếu bạn làm, bạn có thể thực hiện nó.
Bạn có thể sẽ cần một kết quả gọi lại trong startSomething(); Tôi đã làm, nhưng điều này không được hiển thị trong mã này.
Nếu bạn vẫn cần câu trả lời, tôi đã đưa ra giải pháp tại http://stackoverflow.com/a/22134635/1336747 – Alessio
@Alessio, tôi không nghĩ giải pháp của bạn thực sự hoạt động. – Sam