1、Started:通过startService()启动,一旦启动,如果没有显式stop的话,它就会一直执行下去,即使程序退出
2、Bound:通过bindService()启动,它一般用于C/S模式:客户端发送请求,并从服务端返回结果。可用于跨进程之间的通讯,当没有绑定该Service的任何客户端时,这个Service便会自动销毁
虽然Service被分为这两种形式,但一个Service可以同时以这2种形式提供服务,只不过在提供不同服务的时候是选择执行onStartCommand()还是onBind()方法.
1、Service,它是所有Service的基类,包括IntentService,但在使用的过程中要注意线程安全
2、IntentService,基于线程考虑而退出的Service的子类,通过查看它的源码,可知是通过Handler消息机制保证线程的安全,在使用过程中,只需要重写onHandleIntent()方法处理Intent
创建
1、Started: 通过startService创建,有两种情况:
如果该Service未在后台运行,则调用onCreate() -> onStartCommand()
如果该Service已经在后台运行,则条用onStartCommand()
2、Bound:通过bindService创建,该Service必须提供onBind方法的实现
销毁:
1、Started: stopSelf()或者stopService(),注意,当有同时有多个请求给onStartCommand时,不能立刻stop该Service,因为处理完一个请求后可能还有另外一个请求,如果直接stop,那就会影响到第二个请求。正确的做法是:使用stopSelf(id),该id是通过onStartCommand传紧来的Service的id
2、Bound:通过unBindService()
在Service必须实现onBind()接口并且返回IBinder对象。client通过bindService()访问Service,而且client要通过ServiceConnection建立与Service的连接,当连接建立成功后,会调用 onServiceConnected()。 注意:建立连接时一个异步的过程,所以在bindService()方法调用后并不能立刻建立连接,不能立刻使用Service所提供的服务。在Actviity的onCreate()使用会报异常,要在Activity的onResume()后使用Service所提供的服务。
为了创建Bound Service,必须提供实现IBinder接口的对象,有3种方式提供这样的接口:
1、通过继承Binder类: 此时client和service运行在同一个进程中,使用该方法时,Service几乎不是一个后台的工作者,如果要和其他进程进行交互,那就要使用其他方式。
2、使用Messager:此方法可以进程间通讯,该方法使用Handler实现消息的传递,这是最简单的IPC通讯,因为使用了Handler,每次只有一个任务执行,保证了线程安全。
3、使用AIDL:该方法可以进程间 通讯,并且可通过并发处理多个任务请求。未了使用AIDL,你必须创建一个.aidl文件,并定义一些接口,此时android会自动创建一个实现该接口的抽象类,在使用的时候,继承android自动创建的这个类,便可提供服务。
1、继承自Binder类
建立步骤
- 建立一个Binder的子类实例
- 通过onBinder返回该实例
- 在Activity的onServiceConnected()获得该binder
public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
2、使用Messenger如何使用:
- Service创建一个可以从client接收请求的Handler
- 该Handler用于创建一个Messager
- Messager创建了onBind()所需要的IBinder对象
- client使用IBinder对象初始化Messager(引用Service的Handler),然后使用它给Service传递消息
- Service在Handler的handleMessage()接收消息
public class MessengerService extends Service { /** Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mBound; /** * 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 object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); mBound = true; } 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; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // Create and send a message to the service, using a supported 'what' value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } }
注:在该例子中,Service客户端不能接收来自于Service的消息,如果要使用双向的消息可如下实现ApiDemo的(MessengerService.java (service) 、MessengerServiceActivities.java (client)):
MessengerService.java The file containing the source code shown below is located in the corresponding directory in <sdk>/samples/android-<version>/... /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.apis.app; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; 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.widget.Toast; import java.util.ArrayList; // Need the following import to get access to the app resources, since this // class is in a sub-package. import com.example.android.apis.R; import com.example.android.apis.app.RemoteService.Controller; /** * This is an example of implementing an application service that uses the * {@link Messenger} class for communicating with clients. This allows for * remote interaction with a service, without needing to define an AIDL * interface. * * <p>Notice the use of the {@link NotificationManager} when interesting things * happen in the service. This is generally how background services should * interact with the user, rather than doing something more disruptive such as * calling startActivity(). */ public class MessengerService extends Service { /** For showing and hiding our notification. */ NotificationManager mNM; /** Keeps track of all current registered clients. */ ArrayList<Messenger> mClients = new ArrayList<Messenger>(); /** Holds last value set by a client. */ int mValue = 0; /** * Command to the service to register a client, receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client where callbacks should be sent. */ static final int MSG_REGISTER_CLIENT = 1; /** * Command to the service to unregister a client, ot stop receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client as previously given with MSG_REGISTER_CLIENT. */ static final int MSG_UNREGISTER_CLIENT = 2; /** * Command to service to set a new value. This can be sent to the * service to supply a new value, and will be sent by the service to * any registered clients with the new value. */ static final int MSG_SET_VALUE = 3; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @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_VALUE: mValue = msg.arg1; for (int i=mClients.size()-1; i>=0; i--) { try { mClients.get(i).send(Message.obtain(null, MSG_SET_VALUE, mValue, 0)); } 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); } } break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. showNotification(); } @Override public void onDestroy() { // Cancel the persistent notification. mNM.cancel(R.string.remote_service_started); // Tell the user we stopped. Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show(); } /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } /** * Show a notification while this service is running. */ private void showNotification() { // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.remote_service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis()); // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(this, getText(R.string.remote_service_label), text, contentIntent); // Send the notification. // We use a string id because it is a unique number. We use it later to cancel. mNM.notify(R.string.remote_service_started, notification); } }
MessengerServiceActivities.java The file containing the source code shown below is located in the corresponding directory in <sdk>/samples/android-<version>/... package com.example.android.apis.app; import com.example.android.apis.R; import com.example.android.apis.app.LocalServiceActivities.Binding; 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.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MessengerServiceActivities { /** * Example of binding and unbinding to the remote service. * This demonstrates the implementation of a service which the client will * bind to, interacting with it through an aidl interface.</p> * * <p>Note that this is implemented as an inner class only keep the sample * all together; typically this code would appear in some separate class. */ public static class Binding extends Activity { /** Messenger for communicating with service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mIsBound; /** Some text view we are using to show state information. */ TextView mCallbackText; /** * Handler of incoming messages from service. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MessengerService.MSG_SET_VALUE: mCallbackText.setText("Received from service: " + msg.arg1); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * 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_REGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); // Give it some value as an example. msg = Message.obtain(null, MessengerService.MSG_SET_VALUE, 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(Binding.this, R.string.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(Binding.this, R.string.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(Binding.this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; mCallbackText.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, MessengerService.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; mCallbackText.setText("Unbinding."); } } /** * Standard initialization of this activity. Set up the UI, then wait * for the user to poke it before doing anything. */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.messenger_service_binding); // Watch for button clicks. Button button = (Button)findViewById(R.id.bind); button.setOnClickListener(mBindListener); button = (Button)findViewById(R.id.unbind); button.setOnClickListener(mUnbindListener); mCallbackText = (TextView)findViewById(R.id.callback); mCallbackText.setText("Not attached."); } private OnClickListener mBindListener = new OnClickListener() { public void onClick(View v) { doBindService(); } }; private OnClickListener mUnbindListener = new OnClickListener() { public void onClick(View v) { doUnbindService(); } }; } }
3、AIDL(略)
1、记得在调用bind的同时,也不要忘记调用unbind
2、如果你只需要Service在Activity可见的情况下运行,可在onStart()下绑定,在onStop()下解绑,其他同理
3、注意在onResume()和onPause()中绑定和解码Service的使用,因为如果有多个Activity都绑定到该服务,那么该服务便会频繁的绑定和解码,会消耗大量资源