Android 四大组件之Service
---恢复内容开始---
1,Service的生命周期
onCreate第一次创建service的时候调用。
onStartCommand启动service的时候调用。
onStart(This method was deprecated in API level 5. Implement onStartCommand(Intent, int, int)
instead.)
onDestroy销毁的时候调用。
2,进程优先级(由高到低):(红色字体的两个进程是经常被系统回收的两个进程)
1. Foreground process 前台进程 用户正在操作的应用程序的进程.
2. Visible process 可视进程 用户可以看到, 但无法进行操作的应用程序的进程.
3. Service process 服务进程 后台运行的服务所在的进程.(如果有Activity再前台,则该进程属于前台进程)
4. Background process 后台进程 最小化应用程序, 托管到后台运行.
5. Empty process 空进程 已经退出的程序, 没有任务在运行.
3,service的使用注意事项:
1.是否可以在service里写一些费时操作? 不能。如果有耗时操作可能会导致ANR的发生。 (onReceive方法内是否可以写耗时操作?原因)
原因是:service这些回调方法的代码是运行在主线程上的。
2.IntentService 该服务已经启动了一个线程,你不必再启动了。你要做的事情直接写到onHandleIntent,它会在子线程里处理。
三道面试题:
- service和activity的区别。
- activity可以和用户交互,service可以在后台做些事情而不用跟用户交互。
- activity在退出程序后会退出,而对于service,如果没有显示的调用停止服务,那么服务就没有结束,它仍在后台运行。
- 最大的区别应该是:没有服务运行的后台进程叫后台进程,而有服务的后台进程叫服务进程。安卓系统的内存回收经常会回收掉优先级低的后台进程。
- 既然程序已经退出,为什么还保留空进程?
- 优化用户体验。当用户下次启动该APP的时候,无需重新给分配进程,节约时间,提高效率。只有当内存不足时采取回收资源。
- service和线程都是在后台运行,那他们之间有什么关系?
- service和线程不是一个范畴的东西。service是四大组件之一,是一个特殊的类,在service中可以另起线程。service本身不是运行在一个单独进程中,默认情况下service是运行在主线程中的。
service的具体使用:
- 在activity中启动service与停止service
1 //启动服务 2 Intent intent = new Intent(this,MyService.class); 3 startService(intent); 4 //停止服务 5 Intent intent = new Intent(this, MyService.class); 6 stopService(intent);
2,activity通过绑定service,可以调用服务内的方法(activity如果关闭的话,service也会结束)
//在Activity中调用本地服务(同一个应用中的服务)中的方法: //1.调用bindservice去绑定服务,传递一个连接桥对象 //2.在service内部去继承一个Binder,实现的子类 。该子类可以随意调用service内的方//法。 //3.在onBind方法中,返回该子类的实现。 //4.当绑定ok,连接桥建立成功之后,连接桥对象的onServiceConnected 会被调用到, 这里面会返回一个IBinder对象,该对象就是onBind返回的那个。 //5.拿到这个IBinder对象之后,强转为MyBinder接收,然后调用其方法即可。 //绑定和解绑服务 public void bindservice(View view){ //绑定服务 Intent intent = new Intent(this, MyService.class); myServiceConnection = new MyServiceConnection(); bindService(intent, myServiceConnection, BIND_AUTO_CREATE); } public void unbindservice(View view){ //解绑服务 if(myServiceConnection!=null){ unbindService(myServiceConnection); } } public void callLocalServiceMetod(View view){ //调用本地方法 if(binder!=null){ Log.i("MyService","调用本地方法"); final String callParentMethod = binder.callParentMethod(); final int count = binder.getcount(); Toast.makeText(this,callParentMethod+count,Toast.LENGTH_SHORT).show(); } } class MyServiceConnection implements ServiceConnection{ //服务建立起来的时候调用 @Override public void onServiceConnected(ComponentName name, IBinder service) { if(service!=null){ binder = (MyService.MyBinder) service; } Log.i("MyServiceConnection","onServiceConnected"); } //服务连接断开的时候调用 //onServiceDisconnected() 在连接正常关闭的情况下是不会被调用的, 该方法只在Service 被破坏了或者被杀死的时候调用. // 例如, 系统资源不足, 要关闭一些Services, // 刚好连接绑定的 Service 是被关闭者之一, 这个时候onServiceDisconnected() 就会被调用。 @Override public void onServiceDisconnected(ComponentName name) { Log.i("MyServiceConnection","onServiceDisconnected"); } } //service方法 public class MyService extends Service { public int count; public boolean flag=true; public MyService() { } public String getName(){ return "I am MyService"; } class MyBinder extends Binder{ //binder是用来传输数据的 public String callParentMethod(){ return getName(); } public int getcount(){ return count; } } @Override public IBinder onBind(Intent intent) { Log.i("MyService", "onCreate"); new Thread(){ @Override public void run() { super.run(); //一绑定上就开始做服务 while(flag){ count++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i("通过绑定的服务开始了",""+count); } } }.start(); //调用本地方法是的返回值 return new MyBinder(); // } @Override public void onCreate() { super.onCreate(); Log.i("MyService","onCreate"); } @Override public void onDestroy() { super.onDestroy(); Log.i("MyService", "onDestroy"); flag=false; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("MyService", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
3,进程间通信(IPC)(Android使用一种接口定义语言AIDL(Android Interface Definition Language)来公开服务的接口的方式来暴露服务接口)
进程间通信实现过程: 1. 定义服务类. 2. 定义aidl接口文件. 3. 在服务中onbind方法中返回实现aidl接口stub的对象. 4. 在另一个程序中调用bindService方法绑定服务. 5. 拷贝aidl接口文件(包括包名)到另一个程序中. 6. 在onServiceConnected方法中把Ibinder对象转换成aidl接口对象. 7. 使用接口对象调用方法(至此调用到远程服务的方法, 实现进程间通信) //被调用的远程service //接口 package com.rgd.day16_bindservice; // Declare any non-default types here with import statements interface MyAIDLInterface { String callParentMethod(); int getcount(); } //远程service要写的 class MyBinder2 extends MyAIDLInterface.Stub{ @Override public String callParentMethod() throws RemoteException { return getName(); } @Override public int getcount() throws RemoteException { return count; } } //本地调用要写的 class MyConnection implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { if(service!=null){ binder = MyAIDLInterface.Stub.asInterface(service); } } @Override public void onServiceDisconnected(ComponentName name) { } } public void bindremoteservice(View view){ //绑定远程服务 Intent intent = new Intent(); intent.setAction("com.ren.myservice"); intent.setPackage("com.rgd.day16_bindservice"); myConnection = new MyConnection(); bindService(intent, myConnection,BIND_AUTO_CREATE); } public void unbindremoteservice(View view){ //解绑远程服务 if(myConnection!=null){ unbindService(myConnection); } } public void callremoteServiceMetod(View view){ //调用远程服务的方法 if(binder!=null){ try { String s = binder.callParentMethod(); int getcount = binder.getcount(); Toast.makeText(this,s+getcount,Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } }