Service

https://www.jianshu.com/p/8d0cde35eb10

https://blog.csdn.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 不存在了),对应服务的生命周期与上述相同

一.通过startService方式启动的Service

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的生命周期为:

onCreate-->onStart(可多次调用) -->onDestroy
onStartCommand()函数返回值
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()      系统调用这个来传送在serviceonBind()中返回的IBinder;

和onServiceDisconnected()方法      service的连接意外丢失时调用(service崩溃了或被强杀了)

     在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
特别注意:
1、在调用 bindService 绑定到Service的时候,就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自动解除,并且Service会自动停止);
2、使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService;
3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;
4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。
5、应当使用 onStartCommand 而不是 onStart。
     长按home调出最近运行历史,在这里面清除软件。这时候Service调用了onTaskRemoved函数。在一般情况下 没调用onTaskRemoved函数的话 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.使用广播


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值