“点滴芭蕉心欲碎,声声催忆当初。欲眠还展旧时书。鸳鸯小字,犹记手生疏。
倦眼乍低缃帙乱,重看一半模糊。幽窗冷雨一灯孤。料应情尽,还道有情无?”
--------临江仙·点滴芭蕉心欲碎
对于Android开发中常用的知识四大组件之一Service是一个非常重要的知识点,在之前面试的时候遇到了一系列问题,都是不注重细节(基础知识),若要向上走我们必须了解乃至加深对于基础知识点的理解。下面我将进行service的开发中用到的知识点进行总结。
一、 service的适用场景:
- 用于长期执行某些操作,并且甚至与UI(主)线程没有交互。比如启动app直接去网络下载文件
- 跨进程间通信,比如appA程序中Service被appB中程序调用
注意:
Service默认时运行在它所在的宿主进程的主进程中,也就是说如果我们在Service中做耗时工作,UI(主)线程会卡死,出现ARN程序无响应现象。为了防止这种情况出现,我们一般都是在Service中创建一个新的线程来处理一些耗时工作,这样就不会阻塞主线程。从这里也侧面反映了Service不是另一个独立的进程,Service自己本身不会开辟新的进程,除非手动来设置。默认情况下,Service是运行在本运用程序所属的进程中。
二、生命周期
三、Service的两种类型
- Started
- 如果一个应用程序组件(比如一个activity)通过调用startService()来启动服务,则该服务就是被“started”了。一旦被启动,服务就能在后台一直运行下去,即使启动它的组件已经被销毁了。 通常,started的服务执行单一的操作并且不会向调用者返回结果。比如,它可以通过网络下载或上传文件。当操作完成后,服务应该自行终止。
- Bound
- 如果一个应用程序组件通过调用bindService()绑定到服务上,则该服务就是被“bound”了。bound服务提供了一个客户端/服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至可以利用进程间通信(IPC)跨进程执行这些操作。绑定服务的生存期和被绑定的应用程序组件一致。 多个组件可以同时与一个服务绑定,不过所有的组件解除绑定后,服务也就会被销毁。
四、Service注册方式(manifest.xml)
代码如下
<service
android:name=".service.MyService"
android:enabled="true"
android:exported="false">
</service>
官方建议:
- - 为了确保应用的安全性,请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器。
- - 添加 android:exported 属性并将其设置为 "false",确保服务仅适用于您的应用。这可以有效阻止其他应用启动您的服务,即使服务提供了intent过滤器,本属性依然生效。
二、Service的两种启动方式
- StartService()
- 使用startService启动service:
第一次启动service会调用onCreate,onStartCommand,而后面再次startService则不会再调用onCreate而是onStartCommand,并且每次startId不同.
stopService
调用stopService,情况如下:
- 如果service已经通过startService启动,则onDestroy
- 如果service没启动,则没什么效果 - 代码如下:
/**启动服务的事件监听*/
public Button.OnClickListener startService = new Button.OnClickListener(){
public void onClick(View view){
/**单击按钮时启动服务*/
Intent intent = new Intent(MainActivity.this,CountService.class);
startService(intent);
}
};
- 在创建一个自己的service继承Service代码如下:
public class CountService extends Service{
/**创建参数*/
boolean threadDisable ;
int count;
public IBinder onBind(Intent intent){
return null;
}
public void onCreate(){//创建服务
super.onCreate();
/**创建一个线程,每秒计数器加一,并在控制台进行Log输出*/
new Thread(new Runnable(){
public void run(){
while(!threadDisable){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
}
count++;
Log.v("CountService","Count is"+count);
}
}
}).start();
}
public void onDestroy(){//销毁
super.onDestroy();
/**服务停止时,终止计数进程*/
this.threadDisable = true;
}
public int getConunt(){
return count;
}
class ServiceBinder extends Binder{
public CountService getService(){
return CountService.this;
}
}
}
- 注意:这种方式创建的service停止服务的方法是onDestroy()方法
- bindService()
- bindService的参数BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法 得到执行,但onStartCommand()方法不会执行。
- 不同于startService,bind调用后,设置-正在运行里是看不到有Service运行着的.
- 如果没用bindService启动过service(注意:即使是startService启动的也不行),直接调用unbindService,则会崩溃:
java.lang.IllegalArgumentException: Service not registered: yifeiyuan.practice.practicedemos.service.ServiceActivity$1@535f696c - 如果不调用onUnbind,直接关掉Activity,跟unBind效果一样,也就是说两者生命周期相同,共存亡.
- 多个启动服务的请求将会引发服务onStartCommand()方法的多次调用。不过,只有一个终止服务的请求(用stopSelf()或stopService())会被接受并执行。
五、Service类关系
- Service:
- 这是所有服务的基类。如果你要扩展该类,则很重要的一点是:请在其中创建一个新的线程来完成所有的服务工作。 因为服务默认是使用应用程序的主线程的,这会降低应用程序中activity的运行性能。
- IntentService:
- 这是Service类的子类,它使用了工作(worker)线程来处理所有的启动请求,每次请求都会启动一个线程。 如果服务不需要同时处理多个请求的话,这是最佳的选择。 所有你要做的工作就是实现onHandleIntent()即可,它会接收每个启动请求的intent,然后就可在后台完成工作。
- 两者的区别:
- service:
- Service不是一个单独的进程 ,它和应用程序在同一个进程中
- Service不是一个线程,所以我们应该避免在Service里面进行耗时的操作
- intentService:
- 会创建独立的worker线程来处理所有的Intent请求;
- 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
- 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
将知识点总结就在此结束,下一节我会详细介绍service的两种启动方式的代码示例。