为了研究Android服务,我写了一个测试程序,在屏幕上有三个按钮“绑定服务”,“解除绑定服务”和“发送回显”。点击后,他们会使用bindService()
,unbindService()
和Messenger
与服务进行通信。
以下是服务代码:
public class MessengerService extends Service {
private final Messenger mMessenger = new Messenger(new TempHandler());
private class TempHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "Hi, there.", Toast.LENGTH_SHORT).show();
break;
case MSG_SAY_GOODBYE:
Toast.makeText(getApplicationContext(), "See you next time.", Toast.LENGTH_SHORT).show();
break;
case MSG_ECHO:
Toast.makeText(getApplicationContext(), "Received " + msg.arg1 + " from client.", Toast.LENGTH_SHORT).show();
Messenger replyMessenger = msg.replyTo;
Message replyMsg = Message.obtain(null, MSG_ECHO, msg.arg1, 0);
try {
replyMessenger.send(replyMsg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
default:
super.handleMessage(msg);
}
}
}
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "Service bound", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
@Override
public void onDestroy() {
Log.d("", "Service.onDestroy()...");
super.onDestroy();
}
}
这是活动代码:
public class MessengerActivity extends Activity {
private Messenger mMessengerService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
Button bind = (Button) findViewById(R.id.button5);
bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doBindService();
}
});
Button unbind = (Button) findViewById(R.id.button6);
unbind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doUnbindService();
}
});
Button echo = (Button) findViewById(R.id.button7);
echo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doSendEcho();
}
});
}
private void doBindService() {
Intent intent = new Intent(getApplicationContext(), MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private void doUnbindService() {
Message msg = Message.obtain(null, MessengerService.MSG_SAY_GOODBYE);
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
unbindService(mConnection);
}
private void doSendEcho() {
if (mMessengerService != null) {
Message msg = Message.obtain(null, MessengerService.MSG_ECHO, 12345, 0);
msg.replyTo = mMessenger;
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private final Messenger mMessenger = new Messenger(new TempHandler());
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(getApplicationContext(), "Service is connected.", Toast.LENGTH_SHORT).show();
mMessengerService = new Messenger(service);
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mMessengerService = null;
Toast.makeText(getApplicationContext(), "Service is disconnected.", Toast.LENGTH_SHORT).show();
}
};
private class TempHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_ECHO:
Toast.makeText(getApplicationContext(), "Get the echo message (" + msg.arg1 + ")", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
}
当我点击“绑定服务”和“发送回显”按钮时。我可以看到服务已连接,消息通信良好。然后单击“取消绑定服务”,我看到服务onDestroy()
被调用,所以我希望服务停止,不应该再次响应即将发送的消息。但实际上,该服务似乎仍然存在,我可以在单击“发送回显”按钮时再次收到回显消息。所以我想知道我做错了什么吗?或者我可能不完全了解这项服务?
希望有人能提供帮助,谢谢。
答案 0 :(得分:4)
当应用程序组件通过调用bindService()
绑定它时,服务被“绑定”。绑定服务提供客户端 - 服务器接口,允许组件与服务交互,发送请求,获取结果,甚至跨进程间通信(IPC)进行交互。 只要绑定了另一个应用程序组件,绑定服务就会运行。
http://developer.android.com/guide/components/services.html
在所有bindService()
个来电都有相应的unbindService()
来电后,服务会关闭。如果没有绑定的客户端,那么当且仅当某人在服务上调用了startService()时,该服务还需要stopService()。
从以下链接中提取。
How to check if a service is running on Android?
private void doSendEcho() {
if(isMyServiceRunning()) // if service is running
{
if (mMessengerService != null) {
Message msg = Message.obtain(null, MessengerService.MSG_ECHO, 12345, 0);
msg.replyTo = mMessenger;
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MessengerService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
unbindService(mConnection);
Log.i("Stopped!",""+isMyServiceRunning());
Log.i("stopped", "Service Stopped");
}
示例:
我测试了下面的工作正常。
public class MessengerService extends Service {
public static final int MSG_SAY_HELLO =1;
public static final int MSG_SAY_GOODBYE =2;
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
private final Messenger mMessenger = new Messenger(new TempHandler());
private class TempHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
mClients.add(msg.replyTo);
Toast.makeText(getApplicationContext(), "Hi, there.", Toast.LENGTH_SHORT).show();
break;
case MSG_SAY_GOODBYE:
mClients.add(msg.replyTo);
break;
default:
super.handleMessage(msg);
}
}
}
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "Service bound", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
@Override
public void onDestroy() {
Log.i("MessengerService", "Service Destroyed...");
super.onDestroy();
}
}
MainAactivity.java
public class MainActivity extends Activity {
boolean mIsBound=false;
Messenger mService = null;
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MessengerService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bind = (Button) findViewById(R.id.button1);
bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doBindService();
}
});
Button unbind = (Button) findViewById(R.id.button2);
unbind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doUnbindService();
}
});
}
class TempHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_SAY_GOODBYE:
Toast.makeText(MainActivity.this,"Received from service: " + msg.arg1,1000).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new TempHandler());
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = new Messenger(service);
// mCallbackText.setText("Attached.");
// We want to monitor the service for as long as we are
// connected to it.
try {
Message msg = Message.obtain(null,
MessengerService.MSG_SAY_HELLO);
msg.replyTo = mMessenger;
mService.send(msg);
// Give it some value as an example.
// msg = Message.obtain(null,
// MessengerService.MSG_E, this.hashCode(), 0);
// mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
// As part of the sample, tell the user what happened.
Toast.makeText(MainActivity.this, "remote_service_connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
// mCallbackText.setText("Disconnected.");
// As part of the sample, tell the" user what happened.
Toast.makeText(MainActivity.this, "remote_service_disconnected",
Toast.LENGTH_SHORT).show();
}
};
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because there is no reason to be able to let other
// applications replace our component.
bindService(new Intent(MainActivity.this,
MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound=true;
Toast.makeText(MainActivity.this, "Binding",1000).show();
}
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,
MessengerService.MSG_SAY_GOODBYE);
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;
Toast.makeText(MainActivity.this, "UnBinding"+isMyServiceRunning(),1000).show();
}
}
}
答案 1 :(得分:1)
我个人认为术语/术语不满意/误导。 如果将它们称为“FlagForAndroidOSDestruction”和“FlagForAndroidStopService”,则可以更好地理解“onDestroy”和“stopService”。
如果下载/编译/运行以下任何示例,可以看到即使OnHandleIntent已完成或已调用stopService,该过程甚至服务仍然可以随时出现!要看到这个,只需启动下面的示例,然后在手机/平板电脑上转到 设置 - &gt;应用 - &gt;运行 - &gt;显示正在运行的服务 和 设置 - &gt;应用 - &gt;运行 - &gt;显示缓存进程
当你看到这些时,尝试在手机上启动大量其他应用程序,那么你会看到Android销毁所述服务&amp;过程
http://developer.android.com/guide/components/services.html#ExtendingIntentService
http://android-er.blogspot.com/2013/03/stop-intentservice.html
答案 2 :(得分:1)
是的,这是从official docs:
中得出的结论服务既可以启动,也可以绑定连接。在这种情况下,只要系统启动或者使用Context.BIND_AUTO_CREATE标志有一个或多个连接,系统就会保持服务运行。一旦这些情况都不成立,调用服务的onDestroy()方法并且服务被有效终止。从onDestroy()返回时,应完成所有清理(停止线程,取消注册接收器)。
答案 3 :(得分:0)
此链接(Do I need to call both unbindService and stopService for Android services?)表示您需要在unbindService之前调用stopService。
试试。
答案 4 :(得分:0)
来自http://developer.android.com/guide/components/services.html:
这两条路径并非完全分开。也就是说,您可以绑定到已使用startService()启动的服务。例如,可以通过使用标识要播放的音乐的Intent调用startService()来启动背景音乐服务。之后,可能当用户想要对播放器进行一些控制或获取有关当前歌曲的信息时,活动可以通过调用bindService()绑定到服务。 在这种情况下,stopService()或stopSelf()实际上不会停止服务,直到所有客户端解除绑定。
所以你必须在stopService()
之后调用unBindService()