Android Service详解(二)---StartService

Android Service详解(二)---StartService



一丶概述
启动服务由另一个组件通过调用 startService() 启动,这会导致调用服务的 onStartCommand() 方法。

服务启动之后,其生命周期即独立于启动它的组件,并且可以在后台无限期地运行,即使启动服务的组件已被销毁也不受影响。 因此,服务应通过调用 stopSelf() 结束工作来自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。

应用组件(如 Activity)可以通过调用 startService() 方法并传递 Intent 对象(指定服务并包含待使用服务的所有数据)来启动服务。服务通过 onStartCommand() 方法接收此 Intent。

例如,假设某 Activity 需要将一些数据保存到在线数据库中。该 Activity 可以启动一个协同服务,并通过向 startService() 传递一个 Intent,为该服务提供要保存的数据。服务通过 onStartCommand() 接收 Intent,连接到互联网并执行数据库事务。事务完成之后,服务会自行停止运行并随即被销毁。


注意:默认情况下,服务与服务声明所在的应用运行于同一进程,而且运行于该应用的主线程中。 因此,如果服务在用户与来自同一应用的 Activity 进行交互时执行密集型或阻止性操作,则会降低 Activity 性能。 为了避免影响应用性能,您应在服务内启动新线程。

二丶 StartService分类
从传统上讲,可以扩展两个类来创建启动服务:
1.Service
这是适用于所有服务的基类。扩展此类时,必须创建一个用于执行所有服务工作的新线程,因为默认情况下,服务将使用应用的主线程,这会降低应用正在运行的所有 Activity 的性能。
2.IntentService
这是 Service 的子类,它使用工作线程逐一处理所有启动请求。如果您不要求服务同时处理多个请求,这是最好的选择。 您只需实现 onHandleIntent() 方法即可,该方法会接收每个启动请求的 Intent,使您能够执行后台工作。

三丶StartService启动服务的步骤
(如果你使用的是Android Studio那么很好,你可以直接new一个Service出来)
1.创建一个Service(跟你创建一个JAVA类一样的简单方便)
在创建的时候有两个属性选择 
Exported:可扩展,外部可以调用这个Service;
Enable:可用的服务;
如果没有特殊的需求那么可以直接finish
2.这种方式创建后,会在清单文件中自动注册
<service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
3.重写方法
(1)onCreate方法,Start的时候调用一次这个方法;
@Override
public void onCreate() {
    super.onCreate();
}
(2)onStartCommand方法,无论Service启动多少次onCreate只执行一次,但是onStartCommand方法会多次执行,这个方法是实现服务的核心业务
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
}
具体的方法例如
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand");
        for(int i = 0; i < 20;i++){
            Log.e(TAG, "循环"+i+"次");
        }
        return super.onStartCommand(intent, flags, startId);
    }
(3)onDestroy方法,停止Service时调用
@Override
public void onDestroy() {
    super.onDestroy();
}
(4)这个是创建Serivce的时候自动创建的但是在StartService中不需要对其进行修改
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
4.在Mainactivity中实现开启停止服务的方法
(1)开启服务
Intent intent = new Intent(this, MyService.class);
startService(intent);
myService = true;
(2)停止服务(如果服务已经开启才可以停止否则会报错)
if(myService){
    Intent intent = new Intent(this, MyService.class);
    stopService(intent);
}
加入在重写的方法中加入Log打印日志查看他的具体生命周期
点击开启服务会有如下日志

那么如果再次点击呢?如果再次点击则不会再调用onCreate方法

点击结束服务则会打印如下日志


5.stopSelf方法的使用
onStartCommand方法中将操作加入stopSelf可停止服务
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand");
        for(int i = 0; i < 20;i++){
            Log.e(TAG, "循环"+i+"次");
            if(i==15){
                Log.e(TAG, "执行停止任务");
                this.stopSelf();
            }
        }

        return super.onStartCommand(intent, flags, startId);
    }

但是!!!!!!!!!!!!
  使用Service的stopSelf()方法来停止服务,要注意这是一个父类的方法,调用了这个方法之后,服务停止的时间不确定,后面的代码还是会执行,并且onDestroy()方法也会执行,下次重新启动服务的时候,先调用onCreate(),然后再调用onStart()方法。
所以将会打印如下的日志,可以发现确实是停止了服务因为再次点击开启服务执行了onCreate方法


6.如果我想加入耗时操作的时候怎么办呢?
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.e(TAG, "onStartCommand");
    for(int i = 0; i < 20;i++){
        Log.e(TAG, "循环"+i+"次");
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    return super.onStartCommand(intent, flags, startId);
}
如果在服务中加入了耗时操作的话,例如下载或者网络获取时,会阻塞主线程。默认Service与主线程在同一个线程中。点击开启服务按钮时会发现按钮始终处于被点击的状态,这也就是说主线程被阻塞了
那么我们打印一下当前的服务所处的线程吧
Log.e(TAG, "onStartCommand-"+Thread.currentThread().getName());
发现他跟主线程的名字是相同的
所以Service在执行一个耗时操作的时候需要开启一个子线程来完成工作,从而避免阻塞主线程,这个时候打印线程的名字发现与主线程不同;
Log.e(TAG, "onStartCommand-"+Thread.currentThread().getName());
所以Service在执行一个耗时操作的时候需要开启一个子线程来完成工作,从而避免阻塞主线程,这个时候打印线程的名字发现与主线程不同;
//在该方法中实现服务的核心业务
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.e(TAG, "onStartCommand");
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.e(TAG, "onStartCommand-"+Thread.currentThread().getName());
            for(int i = 0; i < 20;i++){
                Log.e(TAG, "循环"+i+"次");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        }
    }).start();
    return super.onStartCommand(intent, flags, startId);
}
而且也不会阻塞主线程
7.那么让我们来看看onStartCommand方法吧
当我们实现这个方法的时候会自动生成如下代码
return super.onStartCommand(intent, flags, startId);
那么他的返回值到底是什么呢?作用又是什么呢?
onStartCommand()方法有四种返回值:
START_STICKY(常量值:1):sticky的意思是“粘性的”。使用这个返回值时,我们启动的服务跟应用程序"粘"在一起,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务。当再次启动服务时,传入的第一个参数将为null;
START_STICKY_COMPATIBILITY(常量值:0)与上个值一样
START_NOT_STICKY(常量值:2):“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT(常量值:3):重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
【备注:】
以上四种情况,可以理解为发生车祸后的人:
START_STICKY:(常量值:1)车祸后自己苏醒,但是失忆;
START_NOT_STICKY:(常量值:2)车祸后再也没有苏醒;
START_REDELIVER_INTENT:(常量值:3)车祸后自己苏醒,依然保持记忆。
START_STICKY_COMPATIBILITY(常量值:0)START_STICKY     的兼容版本,但是不保证服务被kill后会重启
具体的使用直接设置返回值就好:
return Service.START_NOT_STICKY;
默认的是START_STICKY


以上就是StartService了

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值