Служба Android еще жива даже после вызова onDestroy ()?

Для изучения услуги 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() будет вызвана, поэтому я ожидаю, что служба остановится и не будет отвечать на следующее сообщение снова. Но на самом деле сервис кажется еще живым, и я могу получить эхо-сообщение снова, когда нажимаем кнопку «отправить эхо». Поэтому мне интересно, что я сделал неправильно? Или, может быть, я не совсем понимаю о сервисе?

Надеюсь, кто-то может помочь, спасибо.

Служба «привязана», когда компонент приложения связывается с ней, вызывая bindService() . Связанная служба предлагает интерфейс клиент-сервер, который позволяет компонентам взаимодействовать с сервисом, отправлять запросы, получать результаты и даже делать это через процессы с межпроцессорной связью (IPC). Связанная служба запускается только до тех пор, пока к ней привязан другой компонент приложения .

http://developer.android.com/guide/components/services.html

Служба отключится после того, как все bindService() имеют соответствующие unbindService() . Если нет связанных клиентов, то услуге также потребуется stopService (), если и только если кто-то вызвал startService () в службе.

Рисунок из приведенной ниже ссылки.

Как проверить, работает ли служба на 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(); } } } 

Эта ссылка ( Нужно ли мне звонить обеим службам unbindService и stopService для Android? ) Говорит, что вам нужно вызвать stopService перед unbindService.

Попробуй это.

Из http://developer.android.com/guide/components/services.html :

Эти два пути не являются полностью отдельными. То есть вы можете привязать к службе, которая уже была запущена с помощью startService (). Например, услугу фоновой музыки можно запустить, вызвав startService () с намерением, который идентифицирует музыку для воспроизведения. Позже, возможно, когда пользователь захочет осуществлять определенный контроль над игроком или получить информацию о текущей песне, действие может привязываться к службе, вызывая bindService (). В таких случаях stopService () или stopSelf () фактически не останавливают службу до тех пор, пока все клиенты не отвяжут.

Таким образом, вы должны вызвать unBindService () и после stopService ()

Я лично считаю, что терминология / номенклатура является неудовлетворительной / вводящей в заблуждение. «OnDestroy» и «stopService» могут быть лучше поняты, если их называют «FlagForAndroidOSDestruction» и «FlagForAndroidStopService».

Если один загружает / компилирует / запускает любой из следующих примеров, можно видеть, что даже когда OnHandleIntent завершен или прекращен вызов службы, процесс и даже служба все еще могут повесить! Чтобы увидеть это, просто запустите приведенные ниже примеры, а затем на вашем телефоне / планшете перейдите в Настройки-> Приложения-> Запуск-> Показать запущенные службы и настройки-> Приложения-> Запуск-> Показывать кэш-процессы

Когда вы увидите это, попробуйте запустить тонну других приложений на телефоне, и ТОГДА вы увидите, что Android уничтожает упомянутый сервис и процесс.

http://developer.android.com/guide/components/services.html#ExtendingIntentService

http://android-er.blogspot.com/2013/03/stop-intentservice.html

Как проверить все запущенные службы в android?

Да, это вывод, сделанный из официальных документов :

Услуга может быть запущена и связана с ней. В таком случае система будет поддерживать работу службы до тех пор, пока она запущена или есть одно или несколько подключений к ней с помощью флага Context.BIND_AUTO_CREATE. Когда ни одна из этих ситуаций не выполняется, вызывается метод onDestroy () службы, и служба фактически прекращается . Вся очистка (остановка нитей, незарегистрированные приемники) должна быть завершена по возвращении из onDestroy ().