Как вызвать метод в действии с помощью службы
Существует служба, которая слушает какой-то голос. Если голос соответствует строке, в объекте службы вызывается определенный метод.
public class SpeechActivationService extends Service {
public static Intent makeStartServiceIntent(Context pContext){
return new Intent(pContext, SpeechActivationService.class);
}
//...
public void onMatch(){
Log.d(TAG, "voice matches word");
}
//...
}
Вот как я запускаю службу в своей деятельности:
Intent i = SpeechActivationService.makeStartServiceIntent(this);
startService(i);
Из этого метода службы, как я могу вызвать метод, который находится в объекте активности? Я не хочу, чтобы доступ от активности к сервису, но от службы к активности. Я уже читал о обработчиках и вещателях, но не смог найти/понять какой-либо пример. Любые идеи?
Ответы
Ответ 1
Я зарегистрировал BroadcastReceiver в Управлении и передал бы ему намерение из службы.
См. Этот учебник: http://www.vogella.com/articles/AndroidBroadcastReceiver/article.html
Это может выглядеть немного долго, но вы захотите узнать, как их использовать;)
Ответ 2
Предполагая, что ваша служба и активность находятся в одном пакете (т.е. в одном приложении), вы можете использовать LocalBroadcastManager следующим образом:
В вашем сервисе:
// Send an Intent with an action named "my-event".
private void sendMessage() {
Intent intent = new Intent("my-event");
// add data
intent.putExtra("message", "data");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
В вашей деятельности:
@Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
@Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
Из раздела 7.3 ссылки @Ascorbin: http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html#ownreceiver_localbroadcastmanager
Ответ 3
Существует много разных способов достижения этого. Один из них использует классы Handler
и Messanger
. Идея метода состоит в том, чтобы передать объект Handler
с Activity
на Service
. Каждый раз, когда Service
хочет вызвать некоторый метод Activity
, он просто отправляет Message
и Activity
как-то его обрабатывает.
Активность:
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
showToast(msg.what);
}
};
final Intent intent = new Intent(this, MyService.class);
final Messenger messenger = new Messenger(handler);
intent.putExtra("messenger", messenger);
startService(intent);
}
private void showToast(int messageId) {
Toast.makeText(this, "Message " + messageId, Toast.LENGTH_SHORT).show();
}
}
Услуги:
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
final Messenger messenger = (Messenger) intent.getParcelableExtra("messenger");
final Message message = Message.obtain(null, 1234);
try {
messenger.send(message);
} catch (RemoteException exception) {
exception.printStackTrace();
}
}
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Ответ 4
После некоторого исследования я нашел следующие тайминги в моем случае для отправки и получения трансляции. У меня есть сервис в том же процессе.
sendBroadcast (Не рекомендуется, если оба компонента находятся в одном процессе)
34 с
LocalBroadcastManager.getInstance(это).sendBroadcast(намерение);
около 30 секунд
Реализация с использованием AIDL и RemoteCallbackList
Будет работать для одного процесса или другого процесса.
В вашем сервисе
public final RemoteCallbackList<ICallBackAidl> mDMCallbacks = new RemoteCallbackList<ICallBackAidl>();
public void registerDMCallback(ICallBackAidl cb) {
Logger.d(LOG_TAG, "registerDMCallback " + cb);
if (cb != null)
mDMCallbacks.register(cb);
}
Когда вам нужны методы вызова в приложении /Acitvity из службы
public void callMehodsInApplication() {
final int N = mDMCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
mDMCallbacks.getBroadcastItem(i).method1();
} catch (RemoteException e) {
e.printStackTrace();
}
}
mDMCallbacks.finishBroadcast();
}
В вашем классе расширяется приложение или активность.
private ISyncmlServiceDMCallback mCallback = new ISyncmlServiceDMCallback.Stub() {
// Implement callback methods here
public void method1() {
// Service can call this method
}
}
public void onServiceConnected(ComponentName name, IBinder service) {
svc.LocalBinder binder = (svc.LocalBinder) service;
mSvc = binder.getService();
mSvc.registerDMCallback(mCallback);
}
Вызов этого метода почти мгновенен из трансляции и приема из того же процесса