Android组件Service学习
Intent intent = new Intent(MainActivity.this, MyService.class); startService(intent);
Intent intent = new Intent(MyService.SERVICE_INTENT); startService(intent); // @value public static final String SERVICE_INTENT = "com.example.service_ex.SERVICE_INTENT";
<service android:name=".MyService" android:enabled="true" android:permission="com.example.MY_SERVICE_PERMISSION"> <intent-filter> <action android:name="com.example.service_ex.SERVICE_INTENT"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
stopService(new Intent(MainActivity.this ,MyService.class));
// stopService(new Intent(MyService.SERVICE_INTENT)); stopService(new Intent().setAction(MyService.SERVICE_INTENT));
stopSelf(startId); 或者stopSelf();
public class MyService extends Service{ public static final String SERVICE_INTENT = "com.example.service_ex.SERVICE_INTENT"; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show(); //即是放在onCreate中,Service也是会按onCreate--onStartCommand--onDestory顺序执行 //stopSelf(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show(); //内部调用自终止 // stopSelf(startId); return Service.START_STICKY; } @Override public void onDestroy() { Toast.makeText(this, "ENDService", Toast.LENGTH_SHORT).show(); } }
/** * Called by the system every time a client explicitly starts the service by calling * {@link android.content.Context#startService}, providing the arguments it supplied and a * unique integer token representing the start request. Do not call this method directly. * * <p>For backwards compatibility, the default implementation calls * {@link #onStart} and returns either {@link #START_STICKY} * or {@link #START_STICKY_COMPATIBILITY}. * * <p>If you need your application to run on platform versions prior to API * level 5, you can use the following model to handle the older {@link #onStart} * callback in that case. The <code>handleCommand</code> method is implemented by * you as appropriate: * * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java * start_compatibility} * * <p class="caution">Note that the system calls this on your * service's main thread. A service's main thread is the same * thread where UI operations take place for Activities running in the * same process. You should always avoid stalling the main * thread's event loop. When doing long-running operations, * network calls, or heavy disk I/O, you should kick off a new * thread, or use {@link android.os.AsyncTask}.</p> * * @param intent The Intent supplied to {@link android.content.Context#startService}, * as given. This may be null if the service is being restarted after * its process has gone away, and it had previously returned anything * except {@link #START_STICKY_COMPATIBILITY}. * @param flags Additional data about this start request. Currently either * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}. * @param startId A unique integer representing this specific request to * start. Use with {@link #stopSelfResult(int)}. * * @return The return value indicates what semantics the system should * use for the service's current started state. It may be one of the * constants associated with the {@link #START_CONTINUATION_MASK} bits. * * @see #stopSelfResult(int) */ publicint onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY; }
从Android官方文档中,我们知道onStartCommand有4种返回值:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
模拟实现:在运行Service后将其kill掉再重启,观察其startID及Intent参数实参值如下:
1. START_STICKY
可以看出,再次调用 onCreate、onStartCommand,并且 startId = 2, 但是 intent = null
2. START_NOT_STICKY
这次并没有重启。
3. START_STICKY_COMPATIBILITY
只调用了oncreate 方法,没有调用 onStartCommand
4. START_REDELIVER_INTENT
可以看出,再次调用 onCreate、onStartCommand,并且 startId = 1, 但是 intent 不为 null
说明该 int 可以保留上次的 startId 与 intent
一个绑定服务是客户端与服务端之间的一个接口。一个绑定服务允许组件和其进行绑定,并通过这个绑定服务,可以接受请求,发送请求,甚至完成进程间的通信。绑定服务的生命周期以来其绑定的客户端,并非无限期的运行下去。
一个绑定服务,就是一个实现了类Service,并允许其它应用程序与其绑定及与之交互的的组件。提供一个绑定服务,你必须实现onBind()方法,这个方法返回一个IBinder对象,这个对象就是定义用来客户端与服务交互的接口。
客户端通过bindService()方法绑定服务。另外,客户端还必须提供一个ServiceConnection的实现对象,用以监控与服务Service间的连接情况。bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法,并传递一个客户端与服务端可以交互的IBinder接口。
多个客户端同时连接Service时,系统只在第一个客户端连接时调用你的onBind()方法并返回一个IBinder对象,系统在其他客户端进行连接时返回相同的IBinder对象,而不再去调用onBind().
当最后一个客户端调用与服务解除绑定时,系统将销毁服务,除非这个服务启动时,也调用了startService()方法.
有3种方式进行服务绑定:
1、 继承Binder类
如果你的服务只针对你自己的应用程序,且与客户端处于同一个进程当中,那么可以使用继承这种方式。此时,你应该创建一个继续与Binder接口的类,并实现其onBind(),然后返回一个你创建的服务的实例。然后客户端就可以接收到Binder,并可以使用这个Binder访问Binder的public方法及Service的public方法。
2、 使用信使者Messenger
如果你的Service要求跨越不同的进程,那么你需要为你的Service创建一个Messenger成员,同时定义一个可以响应不同类型消息Messge对象Handler对象。
Hander对象是为Messenger对象提供基础的,这样Hander就可以共享一个IBinder对象给客户端了,并允许客户端使用Message对象给服务发送命令。此外,客户端也可以定义一个自己的Messenger,这样客户端就可以将消息发送到服务端了。
3、 使用AIDL
比较复杂的一种,在Messenger基础上支持多线程并发处理。使用AIDL(Android Interface Definition Language),使得Service可以跨应用绑定,AIDL使用系统级的原语定义了Service的接口,允许Android跨进程传递对象。
1、继承Binder类方式实现:
自定义MyBindService继承Service:
/*绑定形式的Service*/ public class MyBindService extends Service{ //为client提供使用的Binder public final IBinder binder = new MyBinder(); public class MyBinder extends Binder { MyBindService getServiceInstance() { return MyBindService.this; } } /*Service生命周期*/ @Override public void onCreate() { Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show(); } @Override public IBinder onBind(Intent intent){ Toast.makeText(this, "onBind", Toast.LENGTH_SHORT).show(); //stopSelf();//使用stopSelf貌似没用 return binder; } @Override public boolean onUnbind(Intent intent) { Toast.makeText(this, "onUnbind", Toast.LENGTH_SHORT).show(); return false; } @Override public void onDestroy() { Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show(); } /*提供相应服务*/ public String provideService() { return "provideService"; } }
public class MainActivity extends Activity { private Button myBind, myUnBind , myUse; //标志是否绑定,判断myBindService=null的方法行不通 private booleanmBind; private MyBindService myBindService; //用以处理client和service private ServiceConnection mConnection = new ServiceConnection() { //调用bindService时系统会调用此函数 @Override public void onServiceConnected(ComponentName name, IBinder service) { //在这里获取MyBindService实例,则可以在Activity中调用Service中的方法 myBindService = ((MyBindService.MyBinder)service).getServiceInstance(); mBind = true; } //当Service意外断开时接收 @Override public void onServiceDisconnected(ComponentName name) { myBindService = null; mBind = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myBind = (Button) findViewById(R.id.myBind); myUnBind = (Button) findViewById(R.id.myUnBind); myUse = (Button) findViewById(R.id.myUse); /*************************绑定Service形式******************************/ myBind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, MyBindService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); /**bind执行流程 onCreate()--onBind(),onBind中需要返回IBinder的实例 bindService调用过程中会自动调用ServiceConnection。onServiceConnected()获得对应的Service实例 通过Service实例调用其提供的服务,并加以控制*/ } }); myUnBind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { /*如果Service没有bind,调用此函数程序将会崩溃 故应当先作判断*/ if (mBind) { unbindService(mConnection); //unBind执行流程 onUnbind--onDestory mBind = false; } else { Toast.makeText(MainActivity.this, "请先bind", Toast.LENGTH_SHORT).show(); } } }); myUse.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mBind && myBindService != null) { Toast.makeText(MainActivity.this, myBindService.provideService(), Toast.LENGTH_SHORT).show(); } } }); } }
public class MessengerService extends Service { /** 自定义消息类型 */ static final intMSG_SAY_HELLO = 1; /**自定义Handler来处理来自client的messages*/ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { caseMSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "MessengerService!",Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * 为IncomingHandler创建Messenger * 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(); } }
在clients端使用得:
public class MainActivity extends Activity { private Button myMessengerBind, myMessengerUnBind, myMessengerUse; private Messenger messenger; private booleanmBindFlag; private ServiceConnection mMessengerConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { messenger = new Messenger(service); mBindFlag = true; } public void onServiceDisconnected(ComponentName className) { messenger = null; mBindFlag = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myMessengerBind = (Button) findViewById(R.id.myMessengerBind); myMessengerUnBind = (Button) findViewById(R.id.myMessengerUnBind); myMessengerUse = (Button) findViewById(R.id.myMessengerUse); myMessengerBind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, MessengerService.class); bindService(intent, mMessengerConnection, Context.BIND_AUTO_CREATE); } }); myMessengerUnBind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mBindFlag) { unbindService(mMessengerConnection); //unBind执行流程 onUnbind--onDestory mBindFlag = false; } else { Toast.makeText(MainActivity.this, "请先bind", Toast.LENGTH_SHORT).show(); } } }); myMessengerUse.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(mBindFlag) { Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { messenger.send(msg); } catch (Exception e) { } } } }); } }
看一下Messenger的源码:
/** * Reference to a Handler, which others can use to send messages to it. * This allows for the implementation of message-based communication across * processes, by creating a Messenger pointing to a Handler in one process, * and handing that Messenger to another process. */ public final class Messenger implements Parcelable { private final IMessenger mTarget; /** * Create a new Messenger pointing to the given Handler. Any Message * objects sent through this Messenger will appear in the Handler as if * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had * been called directly. * * @param target The Handler that will receive sent messages. */ public Messenger(Handler target) { mTarget = target.getIMessenger(); } /** * Send a Message to this Messenger's Handler. * * @param message The Message to send. Usually retrieved through * {@link Message#obtain() Message.obtain()}. * * @throws RemoteException Throws DeadObjectException if the target * Handler no longer exists. */ public void send(Message message) throws RemoteException { mTarget.send(message); } /** * Retrieve the IBinder that this Messenger is using to communicate with * its associated Handler. * * @return Returns the IBinder backing this Messenger. */ public IBinder getBinder() { return mTarget.asBinder(); } /** * Comparison operator on two Messenger objects, such that true * is returned then they both point to the same Handler. */ public boolean equals(Object otherObj) { if (otherObj == null) { return false; } try { return mTarget.asBinder().equals(((Messenger)otherObj) .mTarget.asBinder()); } catch (ClassCastException e) { } return false; } public int hashCode() { return mTarget.asBinder().hashCode(); } public int describeContents() { return 0; } public void writeToParcel(Parcel out, intflags) { out.writeStrongBinder(mTarget.asBinder()); } public static final Parcelable.Creator<Messenger> CREATOR = new Parcelable.Creator<Messenger>() { public Messenger createFromParcel(Parcel in) { IBinder target = in.readStrongBinder(); return target != null ? new Messenger(target) : null; } public Messenger[] newArray(int size) { return new Messenger[size]; } }; /** * Convenience function for writing either a Messenger or null pointer to * a Parcel. You must use this with {@link #readMessengerOrNullFromParcel} * for later reading it. * * @param messenger The Messenger to write, or null. * @param out Where to write the Messenger. */ public static void writeMessengerOrNullToParcel(Messenger messenger, Parcel out) { out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder() : null); } /** * Convenience function for reading either a Messenger or null pointer from * a Parcel. You must have previously written the Messenger with * {@link #writeMessengerOrNullToParcel}. * * @param in The Parcel containing the written Messenger. * * @return Returns the Messenger read from the Parcel, or null if null had * been written. */ public static Messenger readMessengerOrNullFromParcel(Parcel in) { IBinder b = in.readStrongBinder(); return b != null ? new Messenger(b) : null; } /** * Create a Messenger from a raw IBinder, which had previously been * retrieved with {@link #getBinder}. * * @param target The IBinder this Messenger should communicate with. */ public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); } }
3、使用AIDL实现进程间通信IPC
http://blog.csdn.net/wangkuifeng0118/article/details/7277680
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。