Service使用总结

1. 定义一个服务

public class MyService extends Service {
    public MyService() {

    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestory() {
        super.onDestory();
    }
}

(1)onCreate:服务首次创建时执行一次;

(2)onStartCommand:服务启动时就执行(每次调用startService时都会执行);

(3)onDestory:服务销毁时执行一次;

 

2. AndroidManifest.xml文件中注册服务

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="false">
</service>

(1)android:name,指定的是注册的服务类所在的路径(相对路径或完整包路径);

(2)android:enabled,是否启用当前服务;

(3)android:exported,当前服务是否允许其他进程使用;

上面两个步骤基本上就是完整的定义一个服务的流程,下面介绍如何使用服务:

 

3. 启动和停止服务

启动和停止服务也是通过Intent来完成的。例如:

启动服务

Intent startServiceIntent = new Intent(MainActivity.this, MyService.class);
startService(startServiceIntent);

停止服务

Intent stopServiceIntent = new Intent(MainActivity.this, MyService.class);
stopService(stopServiceIntent);

通过startService启动服务后,服务就与启动服务的组件没有关系了,会一直处于运行状态(除非内存不足,系统自动回收),所以我们需要在必要时主动停止服务。还有一种停止服务的方式是在定义服务的MyService类中调用:stopSelf()。

 

4. 活动(Activity)与服务(Service)间的通信

上面的例子中确实能够创建并在activity中启动/销毁一个服务,但是activity却无法与MyService类进行通信。这时就需要通过bindService的方式绑定并创建服务。同时在MyService类中重写onBind方法,借助IBinder实例作为通信媒介。

(1)在MyService类中创建一个子类继承Binder类,定义暴露出去供activity中代码调用的方法:

class DownloadBinder extends Binder {
    public void startDownload() {
        Log.d("MyService", "startDownload");
    }

    public int getProgress() {
        Log.d("MyService", "getProgress");
		return 0;
    }
}

(2)MyService类中实例化自定义的DownloadBinder类,并在onBind中返回该实例:

private DownloadBinder mBinder = new DownloadBinder();

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

(3)在服务的主动绑定方,例如MainActivity中通过匿名类的方式实现ServiceConnection接口:

private MyService.DownloadBinder mDownloadBinder;

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mDownloadBinder = (MyService.DownloadBinder)service;
        mDownloadBinder.startDownload();
        mDownloadBinder.getProgress();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

(1)onServiceConnected:服务连接时调用;

(2)onServiceDisconnected:服务断开时调用;

在onCreate方法中,绑定服务:

protected void onCreate(Bundle savedInstanceState) {
    Intent bindServiceIntent = new Intent(this, MyService.class);
    bindService(bindServiceIntent, connection, BIND_AUTO_CREATE);
}

注:BIND_AUTO_CREATE是一个标志位,表示在绑定时,就自动创建服务,也就是说MyService类中的onCreate方法会执行。

如果想要解绑可以使用:unbindService(connection);

一个服务可以与多个Activity进行绑定,而这些Activity在绑定成功后获取到的IBinder实例都会是同一个。而且如果既调用了startService来开启服务,又调用了bindService来绑定服务(这是允许的),那么在销毁该服务时,必须同时调用stopService和unbindService。

备注1:使用bindService执行服务绑定时,对应的执行方法如下:MyService#onCreate  ->  MyService#onBind  -> ServiceConnection#onServiceConnected。并且每次调用bindService,这三个方法都只会在首次执行一次。

备注2:调用unbindService时,会执行onDestroy方法。

备注3:调用unbindService时,一定要确保服务处于绑定状态,否则会抛出异常(Service not registered),换言之就是不支持多次重复调用unbindService方法。

备注4:通过bindService启动服务时,被启动的服务和Activity会关联起来,所以在退出Activity时,一定要调用unbindService方法进行解绑,或者会抛出异常,提示ServiceConnection泄露的错误。

备注5:onServiceDisconnected并不会在unbindService后执行,onServiceDisconnected只会在服务崩溃或被杀掉后执行,详见官网解释

 

5. 前台服务

后台服务是有可能在内存不足时被系统回收的,此时我们可以创建一个前台服务。同时前台服务还可以关联一个长时间存在的通知(例如某些天气和音乐应用)。

创建前台服务可以通过startForegroundService来完成,但是这是api26中才提供的方法,所以试用前需要判断一下SDK版本,例如:

Intent startProxyServiceIntent = new Intent(this, ProxyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(startProxyServiceIntent);
} else {
    startService(startProxyServiceIntent);
}

将前台服务关联到某个通知:

startForeground(notifyId, notification);

停止前台服务,可以使用stopForeground:

stopForeground(true);  // true表示停止前台服务的同时移除通知栏关联的通知
stopSelf();

 

6. 使用服务的注意事项

(1)服务运行于管理它的进程的主线程上,服务并不会创建自己的线程。如果不想自行在服务创建线程,可以直接使用系统提供的IntentService类,其中的onHandlerIntent方法中的代码默认在工作线程执行。

(2)创建服务存在三种状态:启动状态、绑定状态、二者兼有。

启动状态:通过startService启动服务,仅需要实现onCreate、onStartCommand和onDestory方法,这种方式启动的服务与启动服务的activity生命周期无关,会一直常驻在后台,除非低内存状况下自动回收。

绑定状态:通过bindService绑定的服务,这种方式需要实现onBind方法,并且启动的服务于该服务所绑定的activity生命周期有关,当所有绑定某个服务的activity都解绑后,服务会自行销毁。

二者兼有:不仅通过startService启动服务,同时也在某个activity上通过bindService绑定了该服务。这样如果想要完全销毁该服务,必须调用stopService方法,同时所有相关的activity都主动解绑才行。

(3)安卓系统仅当内存不足且必须回收系统资源来显示用户关注的activity时,才会强制停止服务。如果服务绑定到用户一直关注的activity,则会减小被停止的概率。如果服务被声明为前台运行(前台服务),则基本不会停止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值