Hi,你们好,上一期咱们讲了如何使用BroadcastReceiver,这一期咱们讲解Android四大组件之Service相关知识。天天一篇技术干货,天天咱们一块儿进步。java
耐心专一不只仅是美德,更是一笔财富。android
Service
是一个能够在后台执行长时间运行操做而不提供用户界面的应用组件。Service可由其余应用组件启动,并且即便用户切换到其余应用,Service仍将在后台继续运行。 此外,组件能够绑定到Service,以与之进行交互,甚至是执行进程间通讯 (IPC)。 例如,Service能够处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而全部这一切都可在后台进行。网络
Service
是一个专门在后台处理长时间任务的Android
组件。ide
1.Service
不是一个单独的进程;函数
2.Service
也不是一个单独的线程;this
3.Service
是一个单独的Android组件,Service运行在主线程上,若是想在Service中处理很占时间的操做时,必须在Service中开线程,以下降Activity没有响应的风险;spa
4.Service
不提供用户界面;操作系统
它有两种启动方式:startService
和bindService
。线程
Service有三个常见用途。代理
1.功能调度:Service接收指定的广播信息,从而进一步分析和处理事件,最后修改数据、更新界面或者进行其余相关的操做,调度整个应用使其保持正确的状态。
2.功能提供:Service并不会接收任何的广播,只接收指定的广播提供状态数据,这时须要绑定Service,绑定Service时要管理好Service,通常在Activity的onStop函数里进行解绑unBindService操做。
3.远程调用:定义AIDL服务,跨进程调用Service,先定义一个远程调用接口,而后为该接口提供一个IBinder实现类,客户端获取了远程的Service的IBinder对象的代理后,经过该IBinder对象去回调远程Service的属性或方法。
若是某个程序组件须要在运行时向用户呈现界面,或者程序须要与用户交互,就须要用Activity,不然就应该考虑使用Service。
类似点:
1.都是单独的Android组件;
2.都拥有独立的生命周期;
3.都是Context的派生类,因此能够调用Context类定义的如getResources()
、getContentResolver()
等方法;
4.都拥有本身生命周期回调方法;
不一样点:
1.Activity运行于前台有图形用户界面,负责与用户交互;Service一般位于后台运行,不须要与用户交互,也没有图形用户界面。
随着应用程序启动Service方式不一样,Service的生命周期也略有差别,以下图:
若是应用程序经过startService()方法来启动Service,Service的生命周期如上图左半部分所示。
经过调用startService() 方法启动Service: 当其余组件调用startService()方法时,Service被建立,而且无限期运行,其自身必须调用stopSelf()方法或者其余组件调用stopService() 方法来中止Service,当Service中止时,系统将其销毁。
若是应用程序经过bindService()方法来启动Service,Service的生命周期如上图右半部分所示。
经过bindService() 方法启动Service: 当其余组件调用bindService()方法时,Service被建立。接着客户端经过IBinder接口与Service通讯。客户端经过unbindService() 方法关闭链接。多个客户端能绑定到同一个Service,而且当他们都解除绑定时,系统将销毁Service(Service不须要被中止)
特别说明:当Activity调用bindService()绑定一个已经过startService()启动的Service时,系统只是把Service内部的IBinder对象传给Activity,并不会把该Service生命周期彻底绑定到该Activity,于是当Activity调用unBindService()方法取消与该Service的绑定时,也只是切断该Activity与Service之间的关联,并不能中止该Service组件。要中止该Service组件,还需调用stopService()方法。
在Service
的生命周期里,经常使用的有:
4个手动调用的方法
手动调用方法 | 做用 |
---|---|
startService() | 启动服务 |
stopService() | 关闭服务 |
bindService() | 绑定服务 |
unbindService() | 解绑服务 |
5个自动调用的方法
内部自动调用的方法 | 做用 |
---|---|
onCreate() | 建立服务 |
onStartCommand() | 开始服务 |
onDestroy() | 销毁服务 |
onBind() | 绑定服务 |
onUnbind() | 解绑服务 |
当咱们开始使用Service
的时候固然是启动一个Service了,启动Service的方法和启动Activity很相似,都须要借助Intent来实现,下面咱们就经过一个具体的例子来看一下。
public class MyService extends Service {
public static final String TAG = "MyService";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy() executed");
}
}
复制代码
要建立一个这样的Service,你须要让该类继承Service类,而后重写如下方法:
这几个方法都是回调方法,且在主线程中执行,由Android操做系统在合适的时机调用。
注意:每一个Service
必须在manifest
中 经过来声明。
<service android:name="com.demo.service.MyService" >
...
</service>
复制代码
如今咱们经过继承Service
的方式定义了咱们本身的MyService
类,而且在manifest
中声明了咱们的MyService
,接下来咱们应该启动咱们本身的服务。
第一种方式:咱们是经过一个Intent
对象,并调用startService()
方法来启动MyService
。
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
复制代码
注意:假如咱们是经过点击Button
执行上面的代码,那么第一次点击的时候回执行其中的onCreate()
跟onStartCommand()
方法,可是当咱们第二次点击的时候就只会执行onStartCommand()
方法。
为何会这样呢? 这是因为onCreate()
方法只会在Service
第一次被建立的时候调用,若是当前Service
已经被建立过了(第一次点击建立了MyService
),无论怎样调用startService()
方法,onCreate()
方法都不会再执行。
第二种方式:经过bindService
启动Service
。
bindService
启动服务特色: 1.bindService
启动的服务和调用者之间是典型的client-server
模式。调用者是client
,service
则是server
端。service
只有一个,但绑定到service
上面的client
能够有一个或不少个。这里所提到的client
指的是组件,好比某个Activity
。
2.client
能够经过IBinder
接口获取Service
实例,从而实如今client
端直接调用Service
中的方法以实现灵活交互,这在经过startService()
方法启动中是没法实现的。
3.bindService
启动服务的生命周期与其绑定的client
息息相关。当client
销毁时,client
会自动与Service
解除绑定(client
会有ServiceConnectionLeaked
异常,但程序不会崩溃)。固然,client
也能够明确调用Context
的unbindService()
方法与Service
解除绑定。当没有任何client
与Service
绑定时,Service
会自行销毁。
启动了以后,当咱们想中止服务的时候该怎么作呢?
第一种方式:咱们也是经过一个Intent
对象,并调用stopService()
方法来中止MyService
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
复制代码
第二种方式:调用unbindService(conn)
方法来中止MyService
unbindService(ServiceConnection conn)
复制代码
在上面咱们高高兴兴的启动了Service
了,可是细心的你可能发现了,貌似咱们仅仅只是启动了而已,Activity
跟Service
并无多少"交流",下面咱们就让Activity
跟Service
交流一下。
public class MyService extends Service {
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy() executed");
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class MyBinder extends Binder {
public void startDownload() {
Log.d("TAG", "startDownload() executed");
// 执行具体的下载任务
}
}
}
复制代码
接下来咱们在MainActivity
中经过Button
来绑定Service
和解除绑定
public class MainActivity extends Activity implements OnClickListener {
private Button bindService;
private Button unbindService;
private MyService.MyBinder myBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.startDownload();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService = (Button) findViewById(R.id.bind_service);
unbindService = (Button) findViewById(R.id.unbind_service);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
unbindService(connection);
break;
default:
break;
}
}
}
复制代码
能够看到,这里咱们首先建立了一个ServiceConnection
的匿名类,在里面重写了onServiceConnected()
方法和onServiceDisconnected()
方法,这两个方法分别会在Activity
与Service
创建关联和解除关联的时候调用。在onServiceConnected()
方法中,咱们又经过 向下转型 获得了MyBinder
的实例,有了这个实例,Activity
和Service
之间的关系就变得很是紧密了。如今咱们能够在Activity
中根据具体的场景来调用MyBinder
中的任何public
方法,即实现了Activity
指挥Service
干什么Service
就去干什么的功能。
固然,如今Activity
和Service
其实还没关联起来了呢,这个功能是在Bind Service按钮的点击事件里完成的。能够看到,这里咱们仍然是构建出了一个Intent
对象,而后调用bindService()
方法将Activity
和Service
进行绑定。bindService()
方法接收三个参数,第一个参数就是刚刚构建出的Intent
对象,第二个参数是前面建立出的ServiceConnection
的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE
表示在Activity
和Service
创建关联后自动建立Service
,这会使得MyService
中的onCreate()
方法获得执行,但onStartCommand()
方法不会执行(只有当咱们经过 startService()
方法请求启动服务时,调用此方法)。
解除Activity和Service之间的关联,调用
unbindService(connection);
复制代码
在MyService
的内部经过stopSelf()
方法来销毁的;
一个Service必需要在既没有和任何Activity关联又处理中止状态的时候才会被销毁;
在Service的onDestroy()方法里去清理掉那些再也不使用的资源,防止在Service被销毁后还会有一些再也不使用的对象仍占用着内存;
IntentService
是Service的子类,在介绍IntentService以前,先来了解使用Service时须要注意的两个问题
Service
不会专门启动一个线程执行耗时操做,全部的操做都是在主线程中进行的,以致于容易出现ANR,因此须要手动开启一个子线程;Service
不会自动中止,须要调用stopSelf()
方法 或者 是stopService()
方法中止;使用IntentService
不会出现这两个问题,由于IntentService
在开启Service
时,会自动开启一个新的线程来执行它,另外,当Service
运行结束后,会自动中止。
第一种方式,返回 START_STICKY
或 START_REDELIVER_INTENT
当Service
因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试从新建立此Service
,一旦建立成功后将回调onStartCommand
方法,但其中的Intent
将是null
,除非有挂起的Intent
,如pendingintent
,这个状态下比较适用于不执行命令、但无限期运行并等待做业的媒体播放器或相似的服务。
/** * 返回 START_STICKY 或 START_REDELIVER_INTENT * @param intent * @param flags * @param startId * @return */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
复制代码
第二种方式,提升service的优先权
<service
android:name="com.demo.UploadService"
android:enabled="true" >
<intent-filter android:priority="1000" >
<action android:name="com.demo.MyService" />
</intent-filter>
</service>
复制代码
Service做为Android的四大组件之一,而且项目开发过程当中一些场景下常常被使用到,小伙伴们赶忙上手实操,把它灵活的运用到项目中,结合上两期的Activity和BroadcastReceiver实现有趣的交互吧。
PS:若是还有未看懂的小伙伴,欢迎加入咱们的QQ技术交流群:892271582,里面有各类大神回答小伙伴们遇到的问题哦~