Я не смог найти примеров того, как отправлять сообщения между деятельностью и службой, и я потратил слишком много времени, чтобы понять это. Вот пример проекта для других.
Этот пример позволяет вам запускать или останавливать службу напрямую, а также отдельно привязывать / отменять привязку к службе. Когда служба работает, она увеличивает число до 10 Гц. Если действие связано с Service
, оно будет отображать текущее значение. Данные передаются как целое число и как строка, так что вы можете увидеть, как это сделать двумя разными способами. В упражнении также есть кнопки для отправки сообщений в службу (изменяется значение приращения).
Скриншот:
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exampleservice"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService"></service>
</application>
<uses-sdk android:minSdkVersion="8" />
</manifest>
Res \ значения \ strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ExampleService</string>
<string name="service_started">Example Service started</string>
<string name="service_label">Example Service Label</string>
</resources>
Рез \ расположение \ main.xml:
<RelativeLayout
android:id="@+id/RelativeLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Service" >
</Button>
<Button
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Stop Service" >
</Button>
</RelativeLayout>
<RelativeLayout
android:id="@+id/RelativeLayout02"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btnBind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bind to Service" >
</Button>
<Button
android:id="@+id/btnUnbind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Unbind from Service" >
</Button>
</RelativeLayout>
<TextView
android:id="@+id/textStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Status Goes Here"
android:textSize="24sp" />
<TextView
android:id="@+id/textIntValue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Integer Value Goes Here"
android:textSize="24sp" />
<TextView
android:id="@+id/textStrValue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="String Value Goes Here"
android:textSize="24sp" />
<RelativeLayout
android:id="@+id/RelativeLayout03"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btnUpby1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Increment by 1" >
</Button>
<Button
android:id="@+id/btnUpby10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Increment by 10" >
</Button>
</RelativeLayout>
ЦСИ \ com.exampleservice \ MainActivity.java:
package com.exampleservice;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnStart, btnStop, btnBind, btnUnbind, btnUpby1, btnUpby10;
TextView textStatus, textIntValue, textStrValue;
Messenger mService = null;
boolean mIsBound;
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MSG_SET_INT_VALUE:
textIntValue.setText("Int Message: " + msg.arg1);
break;
case MyService.MSG_SET_STRING_VALUE:
String str1 = msg.getData().getString("str1");
textStrValue.setText("Str Message: " + str1);
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
textStatus.setText("Attached.");
try {
Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
}
catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
textStatus.setText("Disconnected.");
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnStart = (Button)findViewById(R.id.btnStart);
btnStop = (Button)findViewById(R.id.btnStop);
btnBind = (Button)findViewById(R.id.btnBind);
btnUnbind = (Button)findViewById(R.id.btnUnbind);
textStatus = (TextView)findViewById(R.id.textStatus);
textIntValue = (TextView)findViewById(R.id.textIntValue);
textStrValue = (TextView)findViewById(R.id.textStrValue);
btnUpby1 = (Button)findViewById(R.id.btnUpby1);
btnUpby10 = (Button)findViewById(R.id.btnUpby10);
btnStart.setOnClickListener(btnStartListener);
btnStop.setOnClickListener(btnStopListener);
btnBind.setOnClickListener(btnBindListener);
btnUnbind.setOnClickListener(btnUnbindListener);
btnUpby1.setOnClickListener(btnUpby1Listener);
btnUpby10.setOnClickListener(btnUpby10Listener);
restoreMe(savedInstanceState);
CheckIfServiceIsRunning();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("textStatus", textStatus.getText().toString());
outState.putString("textIntValue", textIntValue.getText().toString());
outState.putString("textStrValue", textStrValue.getText().toString());
}
private void restoreMe(Bundle state) {
if (state!=null) {
textStatus.setText(state.getString("textStatus"));
textIntValue.setText(state.getString("textIntValue"));
textStrValue.setText(state.getString("textStrValue"));
}
}
private void CheckIfServiceIsRunning() {
//If the service is running when the activity starts, we want to automatically bind to it.
if (MyService.isRunning()) {
doBindService();
}
}
private OnClickListener btnStartListener = new OnClickListener() {
public void onClick(View v){
startService(new Intent(MainActivity.this, MyService.class));
}
};
private OnClickListener btnStopListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
stopService(new Intent(MainActivity.this, MyService.class));
}
};
private OnClickListener btnBindListener = new OnClickListener() {
public void onClick(View v){
doBindService();
}
};
private OnClickListener btnUnbindListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
}
};
private OnClickListener btnUpby1Listener = new OnClickListener() {
public void onClick(View v){
sendMessageToService(1);
}
};
private OnClickListener btnUpby10Listener = new OnClickListener() {
public void onClick(View v){
sendMessageToService(10);
}
};
private void sendMessageToService(int intvaluetosend) {
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_SET_INT_VALUE, intvaluetosend, 0);
msg.replyTo = mMessenger;
mService.send(msg);
}
catch (RemoteException e) {
}
}
}
}
void doBindService() {
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
textStatus.setText("Binding.");
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.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;
textStatus.setText("Unbinding.");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
}
catch (Throwable t) {
Log.e("MainActivity", "Failed to unbind from the service", t);
}
}
}
ЦСИ \ com.exampleservice \ MyService.java:
package com.exampleservice;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service {
private NotificationManager nm;
private Timer timer = new Timer();
private int counter = 0, incrementby = 1;
private static boolean isRunning = false;
ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
int mValue = 0; // Holds last value set by a client.
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_INT_VALUE = 3;
static final int MSG_SET_STRING_VALUE = 4;
final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
incrementby = msg.arg1;
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI(int intvaluetosend) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, intvaluetosend, 0));
//Send data as a String
Bundle b = new Bundle();
b.putString("str1", "ab" + intvaluetosend + "cd");
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
}
catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
@Override
public void onCreate() {
super.onCreate();
Log.i("MyService", "Service Started.");
showNotification();
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 100L);
isRunning = true;
}
private void showNotification() {
nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
nm.notify(R.string.service_started, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MyService", "Received start id " + startId + ": " + intent);
return START_STICKY; // run until explicitly stopped.
}
public static boolean isRunning()
{
return isRunning;
}
private void onTimerTick() {
Log.i("TimerTick", "Timer doing work." + counter);
try {
counter += incrementby;
sendMessageToUI(counter);
}
catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
Log.e("TimerTick", "Timer Tick Failed.", t);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {timer.cancel();}
counter=0;
nm.cancel(R.string.service_started); // Cancel the persistent notification.
Log.i("MyService", "Service Stopped.");
isRunning = false;
}
}
источник
android:process=:myservicename
атрибут вservice
тег вашего сервиса в файле manifest.xml, например:,<service android:name="sname" android:process=":myservicename" />
тогда он будет запускать ваш сервис как другой процесс, то есть в другом потоке. Это означает, что любой тяжелый расчет, выполненный / длинный запрос службы, не повредит ваш поток пользовательского интерфейса.Ответы:
Посмотрите на пример LocalService .
Ваш
Service
экземпляр возвращает себя потребителям, которые звонятonBind
. Затем вы можете напрямую взаимодействовать со службой, например, регистрируя свой собственный интерфейс слушателя со службой, чтобы вы могли получать обратные вызовы.источник
Android BroadcastReceiver
учебнике. Я использовалLocalBroadcastManager
для постоянного обмена данными между двумяActivity
экземплярами.LocalBroadcastManager
том, что он не блокирует, и вы должны ждать результатов. Иногда вы хотите немедленных результатов.Для отправки данных в сервис вы можете использовать:
А после в сервисе в onStartCommand () получают данные из намерения.
Для отправки данных или события из службы в приложение (для одного или нескольких действий):
Этот метод вызывается из вашего сервиса. Вы можете просто отправить данные для вашей активности.
Для получения события с данными создайте и зарегистрируйте метод registerBroadcastReceivers () в своей деятельности:
Для отправки дополнительных данных вы можете изменить метод
sendBroadcastMessage();
. Помните: вы должны регистрировать трансляции в onResume () и отменять регистрацию в методах onStop ()!ОБНОВИТЬ
Пожалуйста, не используйте мой тип связи между деятельностью и обслуживанием. Это неправильный путь. Для лучшего опыта, пожалуйста, используйте специальные библиотеки, такие как:
1) EventBus от greenrobot
2) Отто от Square Inc
PS В своих проектах я использую только EventBus от greenrobot,
источник
EventBus
иOtto
.Примечание: вам не нужно проверять, работает ли ваш сервис,
CheckIfServiceIsRunning()
потомуbindService()
что запустит его, если он не работает.Кроме того: если вы поворачиваете телефон, вы не хотите его
bindService()
снова, потому чтоonCreate()
будет вызван снова. Не забудьте определить,onConfigurationChanged()
чтобы предотвратить это.источник
Services can be started with Context.startService() and Context.bindService()
Итак, вы отправляете его в сервис. Потом получите.
источник
Все отлично. Хороший пример
activity/service
общения с помощью Messenger .Один комментарий: метод
MyService.isRunning()
не требуется ..bindService()
может быть сделано любое количество раз. никакого вреда в этом нет.Если MyService работает в другом процессе, статическая функция
MyService.isRunning()
всегда возвращает false. Таким образом, нет необходимости в этой функции.источник
Вот как я реализовал Activity-> Service Communication: в моей деятельности у меня было
А потом я использовал это, чтобы начать мой сервис
У меня на службе было
Надеюсь это поможет
источник
Мне кажется, вы могли бы сэкономить память, объявив о своей активности с помощью "Implements Handler.Callback".
источник
Отличный учебник, фантастическая презентация. Аккуратный, простой, короткий и очень понятный. Хотя,
notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
метода больше нет. Как указано здесь , хорошим подходом будет:Проверил себя, все работает как брелок (названия активности и сервиса могут отличаться от оригинала).
источник
Я видел все ответы. Я хочу рассказать самым здравым способом сейчас день . Это заставит вас общаться между
Activity - Service - Dialog - Fragments
(Все).EventBus
Эта библиотека, которую я использую в своих проектах, имеет отличные возможности, связанные с обменом сообщениями.
EventBus в 3 шага
Определите события:
public static class MessageEvent { /* Additional fields if needed */ }
Готовим подписчиков:
Объявите и аннотируйте свой метод подписки, опционально укажите режим потока :
Зарегистрируйте и отмените регистрацию вашего подписчика. Например, в Android действия и фрагменты обычно должны регистрироваться в соответствии с их жизненным циклом:
Опубликовать события:
EventBus.getDefault().post(new MessageEvent());
Просто добавьте эту зависимость в ваш уровень приложения
источник