Service
https://www.jianshu.com/p/8d0cde35eb10
https://blog.****.net/yuzhiboyi/article/details/7558176
声明:此文非本人原创,为整理网络资料加自己的一些注解所得。
1.Service的启动一般都是 某个组件调用startService 或者 bindService
2. 通过Android特有的 Binder IPC机制 通知 ActivityServiceManager ,
3.Ams就会直接通过Binder IPC机制 通知 Service 所在的ActivityThread 把这个服务启动起来 (把这个Service的class文件load到内存)
4.如果是BindService ,Ams还会从Service哪里取到一个binder 然后同样通过IPC传给启动他的Activity
5.Activity 拿到这个binder后就可以和Service通讯了耗时任务同样是需要在异步线程中完成的!
6.当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同
1.context.startService() 的生命周期
context.startService() -> onCreate() -> onStartCommand() -> Service running -> context.stopService() -> onDestroy() -> Service shut down
如果Service还没有运行,则android先调用onCreate(),然后调用onStartCommand();
如果Service已经运行,则只调用onStartCommand(),所以一个Service的onStartCommand方法可能会重复调用多次。
如果stopService的时候会直接onDestroy,如果是调用者自己直接退出而没有调用stopService或者Service.stopSelfResult()的话,Service会一直在后台运行,该Service的调用者再启动起来后可以通过stopService或者Service.stopSelfResult()关闭Service。
所以调用startService的生命周期为:
Service启动之后,如果因为某种意外而停止运行(例如系统回收了该Service),那么系统要自动的把这个Service再运行起来。这个时候,onStartCommand()的返回值就决定了Service重启的行为,
START_STICKY:Service重启(onCreate())之后,会触发onStartCommand(),但是此时onStartCommand()的传入的参数Intent会变成空值,
public class MyService extends Service {
public MyService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent == null) {
//因为这个Service在onStartCommand()返回的是START_STICKY,所以异常退出后,传入的`intent`是空值
}
return START_STICKY;
}
}
START_NOT_STICKY:Service将不会被自动重启,所以也就不会触发onStartCommand();
START_REDELIVER_INTENT:Service重启(onCreate())之后,会触发onStartCommand(),此时onStartCommand()的参数Intent不会变成空值。该Intent将是以前想要启动这个Service的Intent;如果以前有多个Intent想要启动它,那么这里会传入最后一个,也就是最近的一个
2.context.bindService()启动的Service的生命周期(绑定)
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()将返回给客户端一个IBinder接口实例,IBinder允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。 所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
应用组件(客户端)可以调用bindService()绑定到一个service.Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder.绑定是异步的.bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService().ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder.注:只有activities,services,和contentproviders可以绑定到一个service—你不能从一个broadcastreceiver绑定到service.
所以,从你的客户端绑定到一个service,你必须:
1实现ServiceConnection.你的实现必须重写两个回调方法:
onServiceConnected()
系统调用这个来传送在service的onBind()中返回的IBinder.
OnServiceDisconnected()
Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.
2调用bindService(),传给它ServiceConnection的实现.
3当系统调用你的onServiceConnected()方法时,你就可以使用接口定义的方法们开始调用service了.
4要与service断开连接,调用unbindService().
bindService函数的参数
在绑定Service的时候,通常使用的Context.BIND_AUTO_CREATE参数,
1.bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE);
这个绑定就是发了一个请求,当serviceMessenger接收到请求了,他就会考虑要不要去把这个服务实例化。如果不使用Context.BIND_AUTO_CREATE,那么一个Service在没有被运行起来之前,使用bindService()是不会让Service自动运行起来的。如果设置上了这个参数,那么就会让它运行起来,然后进行绑定。
其他参数:
BIND_NOT_FOREGROUND,
BIND_ABOVE_CLIENT,
BIND_ALLOW_OOM_MANAGEMENT,
BIND_WAIVE_PRIORITY,
BIND_IMPORTANT,
BIND_ADJUST_WITH_ACTIVITY
可以用|的方式同时使用其它的标志
2.unbind()函数返回值
自定义Service时,unbind()函数的返回值对Service的生命周期是有影响的。它会决定onRebind()函数是否被调用。
假如一个Service正在运行,此时有个组件C要绑定它,那么会触发onBind()函数;如果C解除绑定,然后又再次绑定,那么不会触发onBind()而是触发onRebind()函数。
public boolean bindService(Intent service, ServiceConnection conn, int flags) { return mBase.bindService(service, conn, flags); }实例化ServiceConnection接口的实现类,重写onServiceConnected() 系统调用这个来传送在service的onBind()中返回的IBinder;
和onServiceDisconnected()方法 service的连接意外丢失时调用(当service崩溃了或被强杀了)
**处理老化测试时异常退出或关机后不能继续老化测试的问题
当系统电量发生变化时,BatteryService通过sendIntentLocked 来告知用户电量发生变化。
在idh.code/frameworks/base/services/core/java/com/android/server/BatteryService.java的sendIntentLocked()中添加
String agingTestService = "com.topwise.agingtestext.util.AgingTestService";
if (isServiceRunning(mContext, agingTestService) == false) {
Log.v("AgingTestService", "no isServiceRunning");
Intent intents = new Intent();
intents.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intents.setClassName("com.topwise.agingtestext", agingTestService);
mContext.startService(intents);
}
/**
* 判断服务是否开启
*/
public static boolean isServiceRunning(Context context, String ServiceName) {
if (("").equals(ServiceName) || ServiceName == null)
return false;
ActivityManager myManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<ActivityManager.RunningServiceInfo> runningService = (ArrayList<ActivityManager.RunningServiceInfo>) myManager
.getRunningServices(30);
for (int i = 0; i < runningService.size(); i++) {
if (runningService.get(i).service.getClassName().toString()
.equals(ServiceName)) {
return true;
}
}
return false;
}
activity和service的交互
activity调用service里面的方法service中有个类部类继承Binder,然后提供一个公有方法,返回当前service的实例。 activity通过bindService来开启一个service,service通过onBind方法,返回一个IBinder实例(我们创建的那个类部类实例),activity中通过onServiceConnected方法,获取IBinder实例,然后再通过IBinder实例来获取service实例,这样,我们得到了service的实例,那么我们的activity就可以随心所欲的使用它里面的各种方法来操作它了。
service操作activity
1.直接把activity传给service,service通过activity实例随便操作activity
2.使用接口回调方式,activity实现相应的接口,service通过接口进行回调,比较灵活
3.使用广播