https://blog.csdn.net/javazejian/article/details/52709857
Service的定义及作用
-
Service(服务) 是一种可以在后台执行长时间运行、没有用户界面的应用组件。
-
作用:执行后台操作、耗时操作(需放到子线程)、进程间通信
-
Service在清单文件中的声明
<service android:enabled=["true" | "false"] android:exported=["true" | "false"] android:icon="drawable resource" android:isolatedProcess=["true" | "false"] android:label="string resource" android:name="string" android:permission="string" android:process="string" > . . . </service>
属性 | 含义 |
---|---|
android:exported | 是否能被其他应用隐式调用,默认值是由service中有无intent-filter决定的, 如果有intent-filter,默认值为true,否则为false。 android:exported 为 false 时,无法被其他应用隐式调用(即使有intent-filter匹配)。 |
android:name | 对应Service类名 |
android:permission | 是权限声明 |
android:process | 是否需要在单独的进程中运行, 当设置为android:process=”:remote”时,代表Service在单独的进程中运行。 注意 “:”很重要,表示,在当前进程名称前面附加上当前的包名 所以“remote”和”:remote”不是同一个意思 前者的进程名称为 remote,而后者的进程名称为:App-packageName:remote |
android:isolatedProcess | 设置 true,表示,服务会在一个特殊的进程下运行 这个进程与系统其他进程分开且没有自己的权限。 与其通信的唯一途径是通过服务的API (bind and start)。 |
android:enabled | 是否可以被系统实例化,默认为 true 因为父标签也有 enable 属性,所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。 |
Service两种启动方式 startService、 bindService 区别及生命周期
1、startService 启动状态
调用 startService() 启动服务时,服务即处于“启动”状态。
一旦启动,服务即可在后台无限期运行,即使启动服务的组件(Activity)已被销毁也不受影响。
手动调用才能停止服务,已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。
2、bindService 绑定状态
调用 bindService() 绑定到服务时,服务处于“绑定”状态。
绑定服务,可以会返回一个Binder对象给客户端,用于C-S交互。
允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。
只有与另一个应用组件绑定时,绑定服务才会运行。
多个组件可以同时绑定到该服务,全部取消绑定后,该服务即会被销毁。
3、Service的一些方法
-
onCreate()
首次创建服务时,系统将调用一次(在调用 onStartCommand() 或onBind() 之前)。
服务已在运行,则不会调用此方法,该方法只调用一次 -
onBind()
调用 bindService() 绑定服务时,onBind() 返回 一个 IBinder 接口的实现类,供客户端用来与服务进行通信。
无论是启动状态、绑定状态,此方法必须重写
在startService启动状态的情况下直接返回 null -
onStartCommand(Intent intent, int flags, int startId)
在绑定状态下,无需实现此方法
每次 startService() 方法启动Service时都会被回调
一旦执行此方法,服务即会启动并可在后台无限期运行。
startService()启动的服务,需要 调用 stopSelf() 或 stopService() 来停止服务-
参数一:intent,启动时,启动组件传递进来的Intent
-
参数二:flags,表示启动请求时是否有额外数据。
flags三个可选值:
(1). 传0,表示没有额外数据
(2) 传 Service.START_FLAG_REDELIVERY
表示 onStartCommand() 方法,返回值为 START_REDELIVER_INTENT,
而且在上一次服务被杀死前会去调用stopSelf方法停止服务。START_REDELIVER_INTENT 表示:当Service因内存不足而被系统kill后,则会重建服务,
并通过传递给服务的最后一个 Intent 调用 onStartCommand(),此时Intent时有值的。(3) 传Service.START_FLAG_RETRY
表示 onStartCommand调用后一直没有返回值时,会尝试重新去调用onStartCommand()。 -
参数三:startId,当前服务的唯一ID
与 stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根据ID停止服务。
-
-
onStartCommand的返回值
(1) START_STICKY
当Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service,
一旦创建成功后将回调onStartCommand方法,但其中的Intent将是null
除非有挂起的Intent,如pendingintent,
比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。(2) START_NOT_STICKY
当Service因内存不足而被系统kill后,即使系统内存再次空闲时,系统也不会尝试重新创建此Service
除非程序中再次调用startService启动此Service,
这是最安全的选项,避免在不必要时、应用能够轻松重启所有未完成的作业时运行服务(3) START_REDELIVER_INTENT
当Service因内存不足而被系统kill后,则会重建服务,并传递给服务的最后一个 Intent 调用 onStartCommand(),
任何挂起 Intent均依次传递。
与START_STICKY不同的是,其中的传递的Intent将是非空,是最后一次调用startService中的intent
适用于主动执行应该立即恢复的作业(例如下载文件)的服务 -
onDestroy()
服务销毁时的回调
清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。
bindService绑定服务的三种实现方式
扩展Binder类、使用Messenger、使用AIDL
当Service处于绑定状态时,其代表着客户端-服务器接口中的服务器。
绑定服务的生命周期通常只在为其他应用组件(如Activity)服务时处于活动状态,不会无限期在后台运行,
宿主(如Activity)解除绑定后,绑定服务就会被销毁
1、扩展Binder类:
服务和客户端还必须在同一进程内,此方式不执行任何跨进程
- 场景:不需要跨进程,服务是提供给自有应用专用的,C-S在相同进程
- 流程:
1)创建BindService服务端,继承自Service并在类中,创建一个实现IBinder 接口的实例对象
2)从 onBind() 回调方法返回此 Binder 实例。
3)在客户端中,从 onServiceConnected() 回调方法接收 Binder,并使用提供的方法调用绑定服务。
-
代码实现
Server端:public class LocalService extends Service{ private final static String TAG = "wzj"; private int count; private boolean quit; private Thread thread; private LocalBinder binder = new LocalBinder(); /** * 创建Binder对象,返回给客户端即Activity使用,提供数据交换的接口 */ public class LocalBinder extends Binder { // 声明一个方法,getService。(提供给客户端调用) LocalService getService() { // 返回当前对象LocalService,这样我们就可在客户端端调用Service的公共方法了 return LocalService.this; } } /** * 把Binder类返回给客户端 */ @Nullable @Override public IBinder onBind(Intent intent) { return binder; } ... }
Client端:
public void doBindService(String packageName) {
Intent intent = new Intent(mContext, LocalService.class);
intent.putExtra(PACKAGE_BUNDLE_KEY, packageName);
/**
* 参数三:flags则是指定绑定时是否自动创建Service。
* 0 代表不自动创建、Context.BIND_AUTO_CREATE 则代表自动创建
*/
mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
public void unBindService(Context context) {
context.unbindService(mConnection);
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
/**
* 绑定服务的时候被回调,在这个方法获取绑定Service的onBind()方法返回的 IBinder,
* 通过这个IBinder对象,实现宿主和Service的交互。
*/
LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
mService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName className) {
/**
* 当取消绑定的时候被回调。但正常情况下是不被调用的,
* 它的调用时机是当Service服务被意外中断时,(例如当服务崩溃或内存不足被终止时)这个方法才被自动调用。
*/
mServerMsger = null;
}
};
2、使用Messenger
Bundle、Message、Messenger都实现了 Parcelable 接口,可以用于跨进程传递数据
-
Messenger 的跨进程方式其底层实现 就是AIDL
使用 Messenger 为服务创建接口,客户端就可利用 Message 对象向服务发送命令
同时客户端也可定义自有 Messenger,以便服务回传消息 -
Messenger 会在单一线程中创建包含所有请求的队列
Messenger是以串行的方式处理客户端发来的消息,C-S交互是线程安全的。 -
过程
-
Service 中实现一个 Handler,接收来自客户端的每个调用的回调
-
Handler 作为 Messenger 构造函数的参数,在创建Messenger时传入
3) Handler # getIMessenger() 返回一个 IMessenger 对象,这是一个 Binder对象,也是Messenger 进程间通信的使用的Binder对象
Service 的 onBind() 中,调用 IMessenger # asBinder() 返回该Binder 对象给客户端 -
客户端收到返回的 IBinder 后,用 Messenger 包装该 Binder,然后使用Messenger将 Message 对象发送给服务(内部用的服务端返回的Binder发送)
发送的消息,都塞入了 Service端的 Handler 的消息队列中。 -
Service 在其 Handler 中(在 handleMessage() 方法中)接收每个 Message
-
代码实现
Server端:public class MessengerService extends Service { static final int MSG_CONNECTED = 1; private static final String TAG ="MessengerService" ; // 创建Messenger并传入Handler实例对象 final Messenger mMessenger = new Messenger(new IncomingHandler()); // 用于接收从客户端传递过来的数据 class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_CONNECTED://收到app进程发来的消息 msg.replyTo.send(Message.obtain(null, MSG_KILL_APP));//通知app进程自杀 break; default: super.handleMessage(msg); } } } /** * 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现 * IBinder接口的实例对象 */ @Override public IBinder onBind(Intent intent) { Log.i(TAG, "Service is invoke onBind"); return mMessenger.getBinder(); } }
Client端:
public class ActivityMessenger extends Activity { //标记 Service 是否已经绑定成功 boolean mBound; // 与服务端交互的Messenger Messenger mService = null; // 实现与服务端链接的对象 private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { /** * 通过服务端传递的IBinder对象,创建相应的Messenger * 通过该Messenger对象与服务端进行交互 */ mService = new Messenger(service); mBound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mBound = false; } }; private void bindService() { //当前Activity绑定服务端 Intent intent = new Intent(getContext(), MessengerService.class); bindService(intent, mConnection,Context.BIND_AUTO_CREATE); } private void unbindServer() { if (mBound) { unbindService(mConnection); mBound = false; } } public void sendToServer() { if (!mBound) return; // 创建与服务交互的消息实体Message Message msg = Message.obtain(null, MessengerService.MSG_CONNECTED, 0, 0); //消息的replyTo指向当前进程中创建的Handler,方便接收Server进程发过来的消息 msg.replyTo = getClientMessenger(); try { //发送消息 mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } /** 创建接收重启进程消息的Messenger */ private Messenger getClientMessenger() { ClientMsgHandler handler = new ClientMsgHandler(mService); Messenger clientMsger = new Messenger(handler); handler.setClientMsger(clientMsger); return clientMsger; } //接收server 发送过来的消息,并发送消息 private static class ClientMsgHandler extends Handler { private Messenger serverMsger; private Messenger clientMsger; public ClientMsgHandler(Messenger serverMsger) { this.serverMsger = serverMsger; } public void setClientMsger(Messenger clientMsger) { this.clientMsger = clientMsger; } @Override public void handleMessage(Message msg) { switch (msg.what) { case MessengerService.MSG_KILL_APP://收到Server端发来的消息 Message restartMsg = Message.obtain(null, MessengerService.MSG_RESTART_APP); restartMsg.replyTo = clientMsger; try { if (serverMsger != null) { //收到消息后,通知Server端 serverMsger.send(restartMsg); } //执行任务 Process.killProcess(Process.myPid()); } catch (Exception e) { e.printStackTrace(); } break; default: super.handleMessage(msg); } } } }
3、使用AIDL
进程间通信,Service 可以同时处理大量并发请求
可以定义 aidl类型的接口,作为进程间调用的回调函数。
因为aidl 类型文件会生成对应的Stub类,该类是继承了Binder类,真正在进程间传递的是对应的Stub类。
代码
-
1)aidl
// IBinderManager.aidl//子进程请求主进程服务成功后,Server端返回给Client的Binder对象
//返回这个管理器Binder,在子进程可以根据binderCode拿到需要的Binder
//这种设计是为了解耦,方便不同业务下把Binder分离interface IBinderManager { IBinder queryBinder(int binderCode); //根据code获取需要的Binder }
//IWebBinder.aidl
//Server提供的Binder对象,可以通过 IBinderManager.queryBinder(int binderCode)获取该Binder interface IWebBinder { /** * methodName: 方法名 jsonParams: 方法参数 callback跨进程回调函数 */ void handleJsFunction(String actionName, String jsonParams, IWebBinderCallback callback); /** * type:消息类型 data:数据 */ void sendEventBus(int type, boolean success, String data); }
//IWebBinderCallback.aidl
// aidl调用后异步回调的接口; // Client通过IWebBinder.handleJsFunction()调用Server端方法时,把该aidl接口作为回调函数 interface IWebBinderCallback { //msgType:回调给web进程的消息类型 message:回调给web进程的消息内容 void onResult(int msgType, String message); }
-
2)aidl 的实现类
/** * Binder管理器 IBinderManager.aidl 的具体实现 * Created by zhangjianliang on 2018/5/22 */ public class BinderManager extends IBinderManager.Stub { public static final int BINDER_WEB_AIDL = 1;//h5进程请求主进程 private Context context; public BinderManager(Context context) { this.context = context; } @Override public IBinder queryBinder(int binderCode) throws RemoteException { IBinder binder = null; switch (binderCode) { case BINDER_WEB_AIDL: { //WebBinderInterface是具体业务相关的Binder对象,这里就不展开代码了 binder = new WebBinderInterface(context); break; } default: break; } return binder; } } /** IWebBinder.aidl 的实现 * 主进程中,封装了给h5进程调用的接口 * Created by zhangjianliang on 2018/5/22 */ public class WebBinderInterface extends IWebBinder.Stub { private Context context; public WebBinderInterface(Context context) { this.context = context; } @Override //处理web进程中h5页面穿过来的事件 public void handleJsFunction(String methodName, String params, IWebBinderCallback callback) throws RemoteException { try { H5Bridge.getInstance().callJava(methodName, params, callback); } catch (Exception e) { e.printStackTrace(); } } @Override public void sendEventBus(int type, boolean success, String data) throws RemoteException { EventBus.getDefault().post(new WebEvent(type, success, data)); } }
-
3)Service
/** * 主进程的服务端,子进程连接该服务,返回Binder,用于在子进程调用主进程的api * Created by zhangjianliang on 2018/5/22 */ public class MainRemoteService extends Service { @Override public IBinder onBind(Intent intent) { return new BinderManager(this);//客户端绑定该Service时,返回的IBinder对象 } }
-
4)Client端
/** * 绑定Service * 这里放到子线程初始化,是为了避免启动服务时阻塞主线程 */ public synchronized void bindMainService(Context context) { ThreadPoolFactory.instance().fixExecutor(new Runnable() { @Override public void run() { mCountDownLatch = new CountDownLatch(1);//共享锁 Intent service = new Intent(context, MainRemoteService.class); if (mConnect == null) { mConnect = new ServiceConnectImpl(); } context.bindService(service, mConnect, Context.BIND_AUTO_CREATE); try { mCountDownLatch.await();//阻塞当前线程(webview子进程的子线程),等待连接完成 } catch (InterruptedException e) { e.printStackTrace(); } } }); } private class ServiceConnectImpl implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (service != null) { mBinderManager = IBinderManager.Stub.asInterface(service); try { //子进程的主线程中监听binder的死亡通知 mBinderManager.asBinder().linkToDeath(new IBinder.DeathRecipient() { @Override public void binderDied() { mBinderManager.asBinder().unlinkToDeath(this, 0); mBinderManager = null; //此处回调到了Server端的主线程中,如果这里重新连接服务就是在主线程连接服务, //如果连接异常有小概率出现anr //可以放到子线程重新请求连接Service } }, 0); } catch (RemoteException e) { e.printStackTrace(); } } //连接成功后,共享锁释放锁,子进程启动服务的线程唤醒继续往下执行 mCountDownLatch.countDown(); } @Override public void onServiceDisconnected(ComponentName name) { } } /** * Client端通过Server返回的IBinder,调用Server的方法,并通过回调函数返回 */ private void callServer() { IBinder binder = null; WebBinderInterface mWebBinder = null; try {//mBinderManager 是Server端返回的Binder对象 if (mBinderManager != null) {//通过 mBinderManager 获取我们业务相关的 Binder对象 binder = mBinderManager.queryBinder(binderCode); } if (binder) { //mWebBinder 是Server端queryBinder(binderCode)返回的IWebBinder.Stub.Proxy 代理 //【这个Proxy是属于Client进程的对象】,不是Server端的 WebBinder真身 mWebBinder = IWebBinder.Stub.asInterface(binder); if (mCallback != null) { mCallback.onServiceConnected(); } } if(mWebBinder == null) { return; } /** * handleJsFunction()是在Client执行的,因为 IWebBinder.Stub.asInterface(binder) 返回的是IWebBinder的代理 * 该代理对象是属于Client端的,不是Server端的WebBinder真身 * Client端的WebBinder.Stub.Proxy 对象执行完Client端的操作后,通过 IWebBinderCallback.Stub 回调到Server端 * 所以 onResult 已经回到Server端执行了 */ mWebBinder.handleJsFunction(action, params, new IWebBinderCallback.Stub() { @Override public void onResult(int msgType, String message) throws RemoteException { if (mActivity != null && !mActivity.isFinishing()) { resolveResult(msgType, message); } } }); } catch (RemoteException e) { e.printStackTrace(); } }
4、bindService 的注意点
-
1)多个Client可以同时连接到一个Service
只有第一个Client绑定时,系统才会调用服务的onBind()方法 来检索IBinder。
随后系统无需再次调用onBind(),便可将同一个IBinder传递给任何其他绑定的Client。
最后一个Client取消与服务的绑定时,系统会将服务销毁。(除非startService也启动了该服务) -
2)在Client生命周期(如Activity的生命周期)的进入和退出时,设置绑定和取消绑定操作
-
只需要在 Activity 可见时与服务交互,则应在 onStart() 期间绑定,在 onStop() 期间取消绑定。
-
希望 Activity 在后台停止运行状态下仍可接收响应,则可在 onCreate()绑定,在 onDestroy()取消绑定。
表示 Activity 在其整个运行过程中(甚至包括后台运行期间)都需要使用服务
如果服务位于其他进程内,那么当提高该进程的权重时,否则低内存时,系统可能会终止该进程
-
3)通常情况下(注意),不要在 Activity 的 onResume() 和 onPause() 期间绑定和取消绑定,
因为每一次生命周期转换都会发生这些回调,这样反复绑定与解绑是不合理的。
onPause执行耗时操作,会阻塞新页面的onResume -
4)我们应该始终捕获 DeadObjectException DeadObjectException 异常
该异常在连接中断时引发的,表示调用的对象已死亡,也就是Service对象已销毁
这是远程方法引发的唯一异常,DeadObjectException继承自RemoteException,因此我们也可以捕获RemoteException异常。 -
5)调用 bindService() 绑定到服务,绑定是异步执行的。
系统随后调用服务的 onBind() 方法,方法返回用于与服务交互的 IBinder
关于启动服务与绑定服务间的转换问题
绑定服务 -> 启动服务、启动服务 -> 绑定服务
Service可以同时是绑定状态和启动状态,系统只会为一个Service创建一个实例对象
所以不管是启动服务还是绑定服务,操作的是同一个Service实例
1、先绑定服务 -> 后启动服务
当前Service先以绑定状态运行,再以启动状态运行,那么绑定服务将【会转为启动服务运行】
这时如果之前 绑定的宿主(Activity)被销毁了,也不会影响服务的运行,服务还是会一直运行下去,
需要调用停止服务、或者内存不足,才会销毁该服务
2、先启动服务 -> 后绑定服务
当前Service 先以启动状态运行,再以绑定状态运行,当前启动服务并【不会转为绑定服务】,
但是还是会与宿主绑定,只是即使宿主解除绑定后,服务依然按启动服务的生命周期在后台运行,
需要调用停止服务、或者内存不足,才会销毁该服务
启动服务 优先级 > 绑定服务
前台服务、通知发送
前台服务:被认为是 用户主动意识到的一种服务,即使内存不足时,系统也不会将其终止
前台服务,必须为状态栏提供通知,除非服务停止或从前台删除,否则不能清除通知。
1、startForeground(int id, Notification notification)
把当前服务设置为前台服务,id参数表示 唯一标识通知 的整型数
提供给 startForeground() 的整型【ID 不得为0】,而 notification是一个状态栏的通知。
2、stopForeground(boolean removeNotification)
用来从前台删除服务,参数布尔值,表示是否也删除状态栏通知,true为删除
【该方法并不会停止服务,只是不再是前台服务】
如果在服务正在前台运行时将其停止,则通知也会被删除。
服务Service、线程Thread的区别
1、两者概念的迥异
-
1)Thread 是程序执行的最小单元,它是分配CPU的基本单位,
当然 Thread 还可以用于执行一些耗时异步的操作。
android系统中UI线程也是线程的一种 -
2)Service是Android的一种无界面组件,运行在主线程上,它是由系统进程托管。
Service 后台任务是指没有UI的组件
2、两者的执行任务迥异
-
1)在android系统中,线程一般指的是工作线程(即后台线程),而主线程主要执行UI绘制和事件分发
如果主线程执行耗时操作会导致ANR -
2)Service 则是android系统中的组件,一般运行于主线程中
因此在Service中是不可以执行耗时操作的,否则系统会报ANR异常。 -
称Service为后台服务,原因是它本身没有UI,用户无法感知,
如果需要让 Service执行耗时任务,可在 Service中开启单独线程去执行。
3、两者使用场景
-
1)耗时操作,都应该使用工作线程(Thread),才能保证UI线程不被占用而影响用户体验。
-
2)需要长时间的在后台运行,且不需要交互,使用服务
比如播放音乐,通过 Service+Notification 方式在后台执行同时在通知栏显示着。
4、两者的最佳使用方式
-
Thread、Service 结合着使用,
比如下载文件,一般会通过 Service + Notification + Thread异步下载
比如 应用程序会维持一个Service来从网络中获取推送服务 -
IntentService:Thread 与 Service 结合执行后台耗时任务
优点:使用方便、代码简洁,不需要我们创建Service实例、同时也创建线程
IntentService 是单个 worker thread,任务需要排队,因此不适合大多数的多任务场景
5、两者的真正关系
两者没有半毛钱关系。
Android 5.0以上 隐式启动问题、解决方案
1、显示启动
Intent intent = new Intent(this,XXXService.class);
startService(intent);
2、隐式启动
需要设置一个Action,把Action的名字设置成Service的全路径名字,在这种情况下 android:exported 默认为true
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.android.ForegroundService");
startService(serviceIntent);
3、隐式启动存在意义
不同应用时,只能用隐式启动。
4、Android 5.0以上的隐式启动问题
-
问题:Android 5.0 之后,禁止了隐式声明Intent来启动Service,使用隐式启动Service,会抛没有指明 Intent 的错误
-
解决:
-
设置 Action、packageName
Intent serviceIntent = new Intent(); serviceIntent.setAction("com.android.ForegroundService"); serviceIntent.setPackage(getPackageName());//设置应用的包名 startService(serviceIntent);
-
将隐式启动转换为显示启动 PackageManager.queryIntentServices()
public static Intent getExplicitIntent(Context context, Intent implicitIntent) { //找出所有匹配 intent 的 Service PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); //确保只有一个匹配的 Service if (resolveInfo == null || resolveInfo.size() != 1) { return null; } //通过 ComponentName 创建Service 组件信息 ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); //创建一个新的 intent Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); //把Service 组件信息设置到 intent中 explicitIntent.setComponent(component); return explicitIntent; } //调用 Intent intent = new Intent();//辅助Intent intent.setAction("com.android.ForegroundService"); //显示的启动服务 Intent serviceIntent = new Intent(getExplicitIntent(this,intent)); startService(serviceIntent);
如何保证服务不被杀死
1、因内存资源不足而杀死Service
-
将 onStartCommand() 方法的返回值,设为 START_STICKY 或 START_REDELIVER_INTENT
表示服务在内存资源紧张时被杀死后,在内存资源足够时再恢复/** * 返回 START_STICKY 或 START_REDELIVER_INTENT */ @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; }
-
将 Service设置为前台服务,这样就有比较高的优先级,在内存资源紧张时也不会被杀掉。
2、用户通过 settings -> Apps -> Running -> Stop 方式杀死Service
-
这个过程会执行 Service 的生命周期,onDestory 方法会被调用,可以在 onDestory() 中发送广播重新启动
这样杀死服务后会立即启动。这种方案是行得通的 -
可开启两个服务,相互监听,相互启动
服务A监听B的广播来启动B,服务B监听A的广播来启动Apublic class ServiceKilledByAppStop extends Service { private BroadcastReceiver mReceiver; private IntentFilter mIF; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Intent a = new Intent(ServiceKilledByAppStop.this, ServiceKilledByAppStop.class); startService(a); } }; mIF = new IntentFilter(); //自定义action mIF.addAction("com.restart.service"); //注册广播接者 registerReceiver(mReceiver, mIF); } @Override public void onDestroy() { super.onDestroy(); Intent intent = new Intent(); intent.setAction("com.restart.service"); //发送广播 sendBroadcast(intent); unregisterReceiver(mReceiver); } }
HandlerThread
1、HandlerThread 是一个线程类,它继承了Thread
2、HandlerThread 有自己的内部 Looper对象,可以进行looper循环;
3、通过获取 HandlerThread 的 looper对象,传递给Handler对象,可以在handleMessage方法中执行异步任务。
4、创建 HandlerThread后,必须先调用HandlerThread.start()方法
Thread会先调用run方法,创建Looper对象。
//创建异步 HandlerThread
HandlerThread handlerThread = new HandlerThread("thread_name");
//必须先开启线程,内部会创建属于该线程的Loop对象
handlerThread.start();
//子线程Handler
Handler childHandler = new Handler(handlerThread.getLooper()) {
@Overide
public void handleMessage(Message msg) {
//在 HandlerThread 线程中执行
}
};
IntentService的使用及原理
-
是一种特殊的 Service, 继承自Service,是一个抽象类
-
可以用于在后台【执行耗时的异步任务,当任务完成后会自动停止】
-
拥有【较高的优先级】,不易被系统杀死(继承自Service的缘故),适合执行一些高优先级的异步任务
-
内部通过 HandlerThread 和 Handler 实现异步操作
-
创建 IntentService时,只需【实现onHandleIntent】和构造方法,onHandleIntent为异步方法,可以执行耗时操作
推荐阅读:
《Android开发艺术探索》 第九章 9.3节Service的工作过程
关于Android Service真正的完全详解,你需要知道的一切
Android 多线程之IntentService 完全详解
Android 多线程之HandlerThread 完全详解