1、Service概念及用途 2、Service生命周期 3、Service与Activity通信 4、IntentService 5、跨进程访问AIDL 6、关于服务的应用 |
一、Service概念及用途 1、Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。 2、其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。 3、一个组件能够绑定到一个service来交互,例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。 4、Service有两种状态,“启动的”和“绑定” |
Service的种类(了解) 按运行地点分类: 其实remote服务还是很少见的,并且一般都是系统服务。 按运行类型分类: 后台服务我们可以自己创建 ONGOING 的 Notification 这样就成为前台服务吗?答案是否定的,前台服务是在做了上述工作之后需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成为 前台服务。这样做的好处在于,当服务被外部强制终止掉的时候,ONGOING 的 Notification 任然会移除掉。 按使用方式分类: 以上面三种方式启动的服务其生命周期也有区别,将在随后给出。 |
类别 | 区别 | 优点 | 缺点 | 应用 |
本地服务(Local) | 该服务依附在主进程上 | 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。 | 主进程被Kill后,服务便会终止。 | 非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。 |
远程服务(Remote) | 该服务是独立的进程, | 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。 | 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。 | 一些提供系统服务的Service,这种Service是常驻的。 |
类别 | 区别 | 应用 |
前台服务 | 会在通知一栏显示 ONGOING 的 Notification, | 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。 |
后台服务 | 默认的服务即为后台服务,即不会在通知一栏显示 ONGOING 的 Notification。 | 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。 |
类别 | 区别 |
startService 启动的服务 | 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService |
bindService 启动的服务 | 该方法启动的服务要进行通信。停止服务使用unbindService |
startService 同时也 bindService 启动的服务 | 停止服务应同时使用stepService与unbindService |
Service 与 Thread 的区别 1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。 2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有! |
二、生命周期 onCreate onStart onDestroy onBind startService: 多次启动服务,startid会上升,强行杀死带服务的进程,则Service的startid会加+; 1、一旦启动,service就在后台运行,即使启动它的应用组件已经被销毁了。 2、通常started状态的service执行单任务并且不返回任何结果给启动者。比如当下载或上传一个文件,当这项操作完成时,service应该停止它本身。 bindService: 只能绑定一次,绑定之后不能再重新绑定,也不能取消绑定两次。 绑定会和当前应用程序共存亡,当前绑定的Activity销毁,自己也会销毁 1、一个绑定的service提供一个允许组件与service交互的接口,可以发送请求、获取返回结果,还可以通过夸进程通信来交互(IPC)。 2、绑定的service只有当应用组件绑定后才能运行,多个组件可以绑定一个service,当调用unbind()方法时,这个service就会被销毁了。 startService和bindService一起使用 特别注意: ***:service与activity一样都存在与当前进程的主线程中,所以,一些阻塞UI的操作,比如耗时操作不能放在service里进行,比如另外开启一个线程来处理诸如网络请求的耗时操作。 1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自动解除,并且Service会自动停止); 2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务 3、同时使用 startService 与 bindService 要注意到,Service 的终止,只需要unbindService,不管 startService 与 bindService 的调用顺序,调用 unbindService 服务再调用stop就会停止。 4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。 5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。 |
1、先start再bind: 那么bind不会再执行oncreate方法,如果按back,只会取消绑定,不会stop服务。 unbind->ondestroy 先unbind再stop: unbind ondestroy 先stop再unbind:执行stop的时候 不会执行destroy的方法,直到执行unbind的时候才会unbind和destroy方法 2、先bind再start: oncreate->bind->onstart unbind->ondestroy 先unbind再stop: unbind ondestroy 先stop再unbind:执行stop的时候 不会执行destroy的方法,直到执行unbind的时候才会unbind和destroy方法 |
三、Service与Activity通信 Activity与Service通信 使用Intent Service与Activity通信 使用 ServiceConnection |
public String getTime(){ String time = new Date().toString(); return time; } class MyBinder extends Binder{ public MyService getMyService(){ return MyService.this; } } @Override public IBinder onBind(Intent intent) { Log.i("msg", "onBind"); return new MyBinder(); } |
ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { Log.i("msg", "onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("msg", "onServiceConnected"); MyBinder myBinder = (MyBinder)service; MyService myService = myBinder.getMyService(); Log.i("msg", myService.getTime()); } }; |
四、IntentService 1、IntentService是继承于Service并处理异步请求的一个类 2、在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样 3、当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。 4、启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行 5、每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。 6、所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。 优点:省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service,第三,it's so easy to use! |
public class MyIntentService extends IntentService { public MyIntentService() { super("name"); } @Override public void onCreate() { Log.i("msg", "onCreate "); super.onCreate(); } @Override protected void onHandleIntent(Intent intent) { Log.i("msg", "onHandleIntent"); try { Thread.sleep(15000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } startService(new Intent(this,MyIntentService.class)); startService(new Intent(this,MyIntentService.class)); 说明:onHandleIntent里面是可以执行耗时操作,并且是以队列的形式一个一个执行 |
五、AIDL跨进程之间的访问 |
Server 1、建立一个aidl的文件 建立在包里面,如果自动在gen里面生命一个IPerson的java文件,则正确 这个java文件是最终继承了BInder对象 2、写一个类继承IPerson,然后实现里面的方法 3、写一个Service类 ,把onBInder方法的返回值设置成Person对象,注册 |
package com.bwf.a75_serviceaidl_server; interface IPerson { void setAge(int age); void setName(String name); String show(); } |
public class Person extends IPerson.Stub{ private String name; private int age; @Override public void setAge(int age) throws RemoteException { this.age = age; } @Override public void setName(String name) throws RemoteException { // TODO Auto-generated method stub this.name = name; } @Override public String show() throws RemoteException { Log.i("msg", "name: "+name+" age: "+age); return "name: "+name+" age: "+age; } } |
@Override public IBinder onBind(Intent intent) { return new Person(); } <service android:name="com.bwf.a75_serviceaidl_server.MyService" android:exported="true"> <intent-filter > <action android:name="com.bwf.service"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service> |
2、Client 1、建一个和Server一样的包名,然后再把IPersonjava类复制过来 2、 |
private IPerson per; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("msg", "onServiceConnected"); per = IPerson.Stub.asInterface(service); try { per.setAge(30); per.setName("Tom"); Log.i("msg", "onServiceConnected "+per.show()); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setAction("com.bwf.service"); bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(conn); super.onDestroy(); } |
六、应用:使用服务播放音乐 |
public class MyService extends Service { private MediaPlayer media; @Override public void onCreate() { Log.i("msg", "onCreate"); media = MediaPlayer.create(this, R.raw.aw); media.setLooping(false); try { media.prepare();//准备 } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("msg", "onStartCommand: "+intent.getStringExtra("info")); switch (intent.getIntExtra("oop", 0)) { case 1://开始音乐 if(media != null && !media.isPlaying() ){ media.start();//播放 } break; case 2://重头开始 if(media != null){ media.seekTo(0); // media.stop(); // media = MediaPlayer.create(this, R.raw.aw); // try { // media.prepare(); // } catch (IllegalStateException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // media.start(); } break; case 3://暂停 if(media != null && media.isPlaying()){ media.pause(); } break; default: break; } return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { Log.i("msg", "onBind"); return null; } @Override public boolean onUnbind(Intent intent) { Log.i("msg", "onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i("msg", "onDestroy"); if(media != null){ media.stop(); media.release();//释放 media = null; } super.onDestroy(); } } |