Service 学习要点
1.Service概述
Service的主要作用是让系统在后台在后台做一些不与用户交互的操作(例如耗时操作:下载网络资源,长期运行的操作:播放音乐)
Service与Thread的区别:(1)Service不是在一个独立的进程中,它与我们的应用程序在同一进程(process)中 (2)Service也不是一个线程,相反,它是运行在主线程的(即UI线程),因此若我们要在Service中进行耗时操作时,需要开启一个子线程,在其中进行耗时操作,否则很容易出现ANR错误(Application Not Responding 程序无响应)
2.Service用法
ServiceTest.java如下:
public class ServiceTest extends Service {
private MyLocalBinder myLocalBinder=new
MyLocalBinder();
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG","onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TAG","onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG","onBind");
return myLocalBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e("TAG","onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("TAG","onDestroy");
}
//对外提供的访问方法
public void downLoad(){
Log.e("downLoad","正在下载...");
}
public void undownLoad(){
Log.e("downLoad","取消下载...");
}
class MyLocalBinder extends Binder{
public ServiceTest getServiceTestInstance(){
return ServiceTest.this;
}
//...这里也可以继续写方法对外提供
}
}
与Activity相似,使用Service也需要通过intent,不能忘记的是在使用Service前,需要在AndroidManifest.xml中进行声明
启动方式一:startService()
通过打印Service的生命周期,我们发现第一次启动Service的时候,会执行onCreate()和onStartCommand(),**
再次启动时,只会执行onStartCommand(),也就是说onCreate()只会在第一次启动的时候进行初始化
**点击“stopService”后,Service被销毁,进入onDestroy()方法。不管我们启动了多少次Service,只要我们在外部调用一次Context.stopService()或者在Service内部调用stopSelf(),Service就会被销毁
上面这种启动方式的缺点:启动完Service后,这个Service就在后台运行了,同时也与启动它的Activity失去了联系,因为不能通过ServiceTest service = new ServiceTest()的方式启动Service,因而我们的Activity中不能获取到ServiceTest的实例。
为了解决与启动Service的组件的通信能力,还有一个解决方案就是通过广播的形式。我们在Activity中发出一些想用操作广播,在Service中注册该广播,Service接收到该广播信息后,完成相应的功能。但是频繁发送广播比较消耗性能,同时,由于广播接受者中的onReceive()中,不能执行长时间的工作,时间超过后,可能就直接跳出了方法。因此,这种方案不是首选。
启动方式二:bindService() Bound机制
通过bindService()方式第一次启动后,会执行onCreate()和onBind()方法,当我们点击“unBindService“时,走的是onUnbind()和onDestroy()方法。如果有另一个组件对同一个Service进行bindService()操作(也就是在bindService()中传入不同的ServiceConnection,此时只会进入onBind()方法,即onCreate()只会在第一次启动的时候进行初始化
总结:可以看到,不管是通过哪种方式启动Service,同一个Service在整个应用程序中只有一个实例存在。区别:(1)两种方式所走的生命周期是不一样的(2)何时被销毁:当我们通过startService()启动时,不管我们启动了多少次Service,只要我们在外部调用一次Context.stopService()或者在Service内部调用stopSelf(),Service就会被销毁;而当我们通过bindService()启动时,前面我们多次启动service后,当所有客户端发出unBindService(),这个Service将被系统销毁。(3)当Service即被startService()启动也被bindService()启动时,这种情况下,Service必须在既没有任何activity关联又停止的情况下,Service才会被销毁。
3.IntentService
我们在第一部分谈到,有时需要在service中进行耗时操作,此时就需要开启一个子线程,而对于这种需求,Android提供了IntentService给用户,intentservice内部已经帮我们开启了线程,我们只需要实现它的onHandleIntent方法,在里面实现我们的功能即可,注:intentservice不能处理多个线程的请求,但是可以处理多个service的请求(此处求解?)
IntentService提供的功能:(1)所有请求处理完成后自动停止服务(2)提供了默认onBind()的实现,直接返回null,意味着我们只能通过startService()的方式启动IntentService
public class MyIntentService extends IntentService
{
public MyIntentService()
{
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.e("MyIntentService","Thread is"+Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("OnDestroy","OnDestroy");
}
}
使用时需注意两点:首先要提供一个无参的构造方法,里面调用父类的有参构造方法,第二是实现onHandleIntent这个抽象方法。
4.前台Service
Service默认都是在后台默默运行的,用户基本察觉不到有Service在运行。此时,Service的优先级是比较低的,当系统资源不足的时候,易被销毁。因此,如果我们想让用户知道有Service在后台运行,如音乐播放器,或者想让Service一直保持运行状态,不容易被系统回收,此时,就可以考虑使用前台Service。前台Service是被认为是用户已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程。
用法:
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG","onCreate");
Notification notification=new Notification(R.mipmap.ic_launcher,"前台通知",System.currentTimeMillis());
Intent intent=new Intent(this,MainActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this,0,intent,0);
notification.setLatestEventInfo(this, "通知标题", "前台Service内容", pendingIntent);
//设置到前台运行,第一个参数为通知notification的唯一ID
startForeground(1,notification);
}
(关于Notification在SDK23以后和SDK22之前用法不一样,上面是SDK22以前的,下面是SDK23以后的)
Notification.Builder builder=new Notification.Builder(getApplication());
builder.setContentInfo("补充内容");
builder.setContentText("主内容区");
builder.setContentTitle("通知标题");
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setTicker("新消息");
builder.setAutoCancel(true);
builder.setWhen(System.currentTimeMillis());
Intent intent = new Intent(getApplication(), MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplication(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(pendingIntent);
Notification notification = builder.build();
如果我们要移除这个前台Service,只需要调用stopService()即可
网友评论