本文讲解内容:
- Service的简单使用
- 普通Service
- IntentService
- Service的绑定操作
- Service的生命周期
- 前台Service的使用
- Android通知栏的使用
1.Service的简单使用
1.1普通Service的简单使用
后台服务的优先级是很低的,当系统内存不足的时候就会被回收.
- 创建Service
- 重写相应的方法
- 启动/关闭服务
1.1.1 创建服务
创建服务的方法就不写了,这里主要说 明一下AndroidManifest中的属性
- android:name Service的类名称
- android:label Service的名字
- android:icon Service的图标
- android:enabled 是否可以被系统实例化,默认是true 因为父标签也有enable属性,所以必须两个都为true的情况下服务才能被激活,否则不会被激活.
- android:exported 代表是否能被其他应用隐式调用,由inter-filter决定,如果为false的情况下,即便你匹配了inter-filter也无法隐式调用
- android:process 是否需要在单独的进程中运行,当设置为android:process = ":remote"时,代表Service在单独的进程中运行.这里注意":"很重要,它的意思是要在当前进程名称前面附加上当前的包名,所以"remote"和":remote"不是同一个意思,前者的进程名称为:remote,而后者的进程名称为: App-packageName:remote.
- android:permission 是权限声明
- android:isolatedProcess 设置true意味着服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限.与其通信的唯一途径就是通过服务的API(bind and start)
1.1.2重写相应的方法
public class GeneralService extends Service {
private String TAG = GeneralService.class.getSimpleName();
public GeneralService() {
}
@Override
public IBinder onBind(Intent intent) {
/*这个是绑定Binder的相应的方法,
*这个服务中先不去考虑
*/
return null;
}
@Override
public void onCreate() {
super.onCreate();
/*
* 创建服务的时候调的回调
* 这个方法只有在创建Service的时候执行一次
*/
Log.e(TAG, "服务创建了");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*
* 具体执行逻辑的时候的方法
* 1.这里有一点问题说明一下,有的时候你创建相应的服务了,但是由于后台资源不足,服务被销毁了
* 这个时候,在执行的时候就会存在相应intent为空的情况,当你遇到这个情况的时候,只要返回相应的标识就可以了
* return Service.START_REDELIVER_INTENT;就能保证服务再次启动的时候intent不为空了
* 2.这个方法每次调用相应的startService都会去执行
*/
Log.e(TAG, "服务正在执行");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
/*
* 销毁服务的回调
* 这个方法只有在销毁Service的时候执行一次
*/
Log.e(TAG, "服务销毁了");
}
}
1.1.3启动/关闭服务
- 开启服务
Intent intent = new Intent(this, GeneralService.class); startService(intent);
- 关闭服务
Intent intent = new Intent(this, GeneralService.class); stopService(intent);
1.1.4这里着重介绍一下相应得方法
- onCreate 服务创建的时候回调的方法
- onBind 绑定服务的时候调用的方法,后面将服务绑定的时候讲解
- onStartCommand 执行逻辑的方法
- onDestory 服务关闭时候的回调方法
相应的执行逻辑:
- 正常的生命周期逻辑(第一次启动)
构造方法()->onCreate()->onStartCommand()->onDestory(); - 当Service存在的情况下再次启动
onStartCommand()
也就是说如果多次点击启动,onCreate()不会多次执行,只有Service销毁的时候再次启动的时候才会执行相应的onCreat()方法,简单理解就是onCreat()方法只有在创建的时候执行一次!
1.2IntentService的简单使用
使用上和上面的内容没有什么出入,只是继承的方法和内部相应的实现有点变化,但是变化不是很大,这里就贴一下相应的内容,不去做相应的具体讲解了,只要记住这个Service能自己调用相应的onDestory()就可以了.
public class IntentService extends android.app.IntentService {
private String TAG = IntentService.class.getSimpleName();
public IntentService() {
super("IntentService");
/*调用父类的构造方法,这里面传入的名字是工作线程的名称,所以这个名称你可以随便传*/
Log.e(TAG, "服务有名字了");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "服务创建了");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
/*
* 在我的理解,这个工作线程只会有一个,因为里面维护了一个相应的Handler
* 每次的耗时操作都会以相应的队列的方式在IntentService中一次执行
* 每次开启服务的时候都会走这个方法,但是我调用相应的Stop无法停止相应的服务
* 这个还有待于研究,因为子停止,或许不需要停止的相应的方法吧(反正相应的停止的方法是不好使的)
*/
for (int i = 0; i < 100; i++) {
Log.e(TAG, "服务正在执行" + i);
}
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
/*这个方法实在o'nHandleIntent之前进行执行
*所以这里可以初始化一些相应的内容
*/
Log.e(TAG, "onStartCommand: 执行了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
/*这个方法会在相应的onHandleIntent执行完成的时候回调*/
Log.e(TAG, "服务销毁了");
}
}
相应的启动方法类似.
但是这里要注意几个问题:
- 当你startService的时候,即使你调用相应的stopService也不会让Service停止下来
- 这个服务不存在相应的stopService的方法了
剩下的基本上注释都有.
2.绑定服务的方法
- 简单的介绍一下为什么要绑定服务
你可能会发现,上面的方法只是启动了服务,但是其实Service和Activity其实根本没有什么关联,在Activity也没有办法去控制Service里面的执行内容,也就是Service脱离了相应的Activity,只是通过Activity启动而已,这个不是我们想看到的,所以才有相应的绑定方法来控制Service.
2.1 绑定服务的写法
上面在开启服务的时候,不知道大家有没有注意到一个细节在onBind()方法中我们返回的是空,为什么这里返回的是空呢???其实这个就是绑定服务所要必须的内容.下面我们开始实现简单的内容吧!
2.1.1创建相应的Binder对象
class MyBinder extends Binder {
public void startBinder() {
Log.e(TAG, "startBinder: ");
}
public void stopBinder() {
Log.e(TAG, "stopBinder: ");
}
}
这里面的方法你可以随便的写,想要什么写什么!!!
2.1.2在相应的Service中创建相应的对象,并在Binder()中返回
private MyBinder mMyBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return mMyBinder;
}
2.1.3启动相应的Service
这个也是这里的重点问题,涉及到一个ServiceConnection
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
/*这个方法会在相应的创建的时候进行调用*/
Log.e(TAG, "onServiceConnected: 连接创建的时候调用");
//向下转型从而调用相应的方法
BindService.MyBinder binder = (BindService.MyBinder) service;
binder.bindService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
/*这个方法是在Service丢失的情况下才被调用
* 或者在Service被杀死的视乎调用*/
}
};
说明一下上面两个回调方法:
- onServiceConnected 系统调用这个方法来传送在Service的onBind中返回的IBinder
- onServiceDisconnected 在Service的链接意外丢失的时候调用这个方法,比如当Service崩溃了或者被越塔强杀了的时候会调用这个方法,但是注意当解除绑定的时候不会调用这个方法.
- 还有一点说明一下:startBinder()这个方法是你自己的方法,也就是说,在这里你就可以控制Service了
//绑定
Intent intent = new Intent(this, BindService.class);
/*参数三有必要说明下:
*BIND_AUTO_CREATE 这个方法是创建关联后自动创建Service,会使得相应Service中的onCreate()方法的到执行
* 但相应的onStartCommand()不会被执行
*/
bindService(intent, mConnection, BIND_AUTO_CREATE);
//解绑
unbindService(mConnection);
2.1.3BindService的生命周期
构造方法->oncreate()->onBind()->onServiceConnected()
当你再次点击的时候不会调用相应的启动的流程了,除非你调用unBind()方法进行相应的取消否则不会去创建的,这里只是创建了连接,让Activity持有了相应的Service可以使用内部的相应方法了!
3.Service的声明周期
- 当你调用startService()的时候生命周期是这样的:
onCreate() -> onStartCommand()
这里注意,要是之前你启动过这个service的话那么onCreate()不会多次调用,除非你调用了** stopService(mIntent);**结束了这个Service否则不会在走onCreate();也就是说生命周期中onCreate()只会执行一次; - 当你调用stopService()的时候生命周期是这样的:
onDestroy() - 当你调用bindService的时候和上面的生命周期类似,这里只是建立了一个持久连接.别无其他.
- boolean onUnBind(Intent intent) 当该Service上绑定得所有客户端都断开连接得时候回调
这里有一个问题是你需要注意的,如果你想在onStartCommand()想结束Service的话,直接调用stopSelf()方法就可以了
3.1几种特殊情况下的生命周期问题
- 当一个Service既被调用了bindService()又调用了startService(),这种情况下你如果想要关闭服务的话,必须两种服务的结束方法都调用才能结束当前的服务.也就是stopService()和unBindService()方法同时执行,这样Service才会走onDestroy()方法.
4.一些服务的特殊使用方法
开机启动服务(其实这个思路很简单,监听开机的广播,然后启动你的服务就可以实现了),下面直接上代码:
- 广播的代码:
public class BootBroadcastReceiver extends BroadcastReceiver {
private static final String mBootAction = "android.intent.action.BOOT_COMPLETED";
private static final String mShutDownAction = "android.intent.action.ACTION_SHUTDOWN";
private static final String TAG = BootBroadcastReceiver.class.getSimpleName();
private Intent mServiceIntent;
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) return;
if (intent.getAction().equals(mBootAction)) {
Log.e(TAG, "onReceive: 监听到开机广播了");
/*这里启动服务*/
mServiceIntent = new Intent(context, MyService.class);
mServiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(mServiceIntent);
} else if (intent.getAction().equals(mShutDownAction)) {
Log.e(TAG, "onReceive: 监听到关机广播了");
if (mServiceIntent != null) {
/*这里关闭服务*/
context.stopService(mServiceIntent);
}
}
}
}
- 广播在清单文件中注册的代码
<receiver
android:name=".BootBroadcastReceiver"
android:enabled="true"
android:exported="true">
<!--开机广播-->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<!--关机广播-->
<intent-filter>
<action android:name="android.intent.action.ACTION_SHUTDOWN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
其实上面的内容加起来就可以启动相应的广播了,但是一定要注意一点就是监听开机广播的时候涉及到权限的问题
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
这个问题千万别忘了...