Android四大组件之Service

进程级别

在Android中,进程是有级别分类的,级别越高,越难杀死,保活就是提高当前应用进程优先级。

Foreground process前台进程

什么是前台进程呢,当你打开一个app就会启动一个activity,这个时候这个app就是前台进程;还有当广播接收者的onReceive方法执行的时候是前台进程。这个不会被杀死。

Visible process可视进程

当你开启activity声明周期执行了onPause方法,页面不可操作,但是还看得见,这时候就是可是进程。

Service process服务进程

在进程里面启动一个服务,听音乐的软件都启动了一个服务,当你退出软件的时候,同样能听音乐,就是因为播放音乐是放到服务里面执行的。
这个进程是看不到的。

Background process后台进程

相当于activity执行了onStop,就是不可见了,比如按下home键,这时候程序并没有被杀死,就是没有执行onDestroy,这时候就是后台进程了

Empty process空进程

这个一直按返回键,退出应用,执行了onDestroy,但是Android系统并不会马上杀死这个进程,这时候进程只一个空进程,当你一直开启其他app,开的太多了,这个空进程就被杀死了。
为啥不马上杀死呢,谷歌是这样解释的,为了提高下一次打开这个应用的速度。
这个进程最容易被杀死。

服务

Android设计服务这个组件,就是为了做一些需要在看不到的时候同样可以进行操作,就像Windows系统一样,任务管理器中有好多服务,但是你都看不到。常见的使用地方是,音乐播放器、后台网络下载,经常有些软件你点了更新,然后就开启服务下载了,你退出应用,还是在下载,就是因为这个下载实在服务中做的,当下载完成了,就开始安装。
服务是看不见的,服务也是四大组件之一,所以也要在清单文件配置一下,服务的声明周期只有三个,onCreate,onStartCommand,onDestroy。因为服务没有页面,所以服务的声明周期就很少只有三个了。

开启服务-----startService

代码怎么写呢,很简单,startService开启服务,只要你不手动关闭,就会长期在后台运行
第一步:定义一个类,继承Service,清单文件配置一下,调用startService就可以了。

public class CustomService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(this.getClass().getName(),"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(this.getClass().getName(),"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(this.getClass().getName(),"onDestroy");
    }
}

下面在清单文件配置一下

<service android:name=".service.CustomService"/>

下面在activity中弄两个按钮,写两个点击事件,一个开始服务,一个关闭服务。

    public void startServiceClick(View view) {
        Intent intent = new Intent(this, CustomService.class);
        startService(intent);

    }

    public void stopServiceClick(View view) {
        Intent intent = new Intent(this,CustomService.class);
        stopService(intent);
    }

开启服务-----bindService

服务类还是上面这个服务类,就是开启方式不同了,需要注意的是,bindService开启的服务,当Activity被销毁了,被这个Activity用bindService开启的服务也就自动销毁了
下面贴出开启的代码

	private MyServiceConnection myServiceConnection;
  public void startServiceClick(View view) {
        Intent intent = new Intent(this, CustomService.class);
//        startService(intent);
        //第一个参数是意图
        //第二个参数是监听服务连接的
        //第三个是标记,BIND_AUTO_CREATE就是自动连接到服务
        myServiceConnection = new MyServiceConnection();
        bindService(intent,myServiceConnection,BIND_AUTO_CREATE);
    }

    public void stopServiceClick(View view) {
//        Intent intent = new Intent(this,CustomService.class);
//        stopService(intent);
        unbindService(myServiceConnection);
    }

    /**
     * 监听服务连接的类
     */
    class MyServiceConnection implements ServiceConnection{
        /**
         * 当服务连接成功的时候调用
         * 注意如果监听的服务的onBind没有返回值,这个方法就不会执行
         * 其实这个监听类,监听的是IBinder
         * @param name
         * @param service
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

        }

        /**
         * 当失去连接的时候调用
         * @param name
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

bindService特点:只能开启一次,只能关闭一次,开启多次或者关闭多次,都会崩溃。

bindService调用服务中的方法

上面说了bindService这种开启方式,但是这样开启的作用是还是什么呢,答案就是这种启动方式可以在服务的外部调用服务内部的方法。这时候就需要用到bindService开启的时候创建的监听类了,这个监听类时间上监听的是IBinder。
我就在上面的开启方式中改造一下吧。

  1. 在服务类中增加往外暴露的方法
public class CustomService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(this.getClass().getName(),"onBind");
        return new MusicBind();
    }
    private void startMusic(){
        Log.e(this.getClass().getName(),"startMusic");
    }
    private void stopMusic(){
        Log.e(this.getClass().getName(),"stopMusic");
    }
    private void nextMusic(){
        Log.e(this.getClass().getName(),"nextMusic");
    }
    private void previousMusic(){
        Log.e(this.getClass().getName(),"previousMusic");
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(this.getClass().getName(),"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(this.getClass().getName(),"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(this.getClass().getName(),"onDestroy");
    }

    public class MusicBind extends Binder{
        public void startMusicBind(){
           startMusic();
        }
        public void stopMusicBind(){
            stopMusic();
        }
        public void nextMusicBind(){
           nextMusic();
        }
        public void previousMusicBind(){
           previousMusic();
        }
    }
}
  1. 开启服务,这步代码就不写了,开启服务就用bindService方法就行了
  2. 在监听服务的类中获取IBinder对象,注意把musicBind 提取到Activity中
 /**
     * 监听服务连接的类
     */
    class MyServiceConnection implements ServiceConnection{
        /**
         * 当服务连接成功的时候调用
         * 注意如果监听的服务的onBind没有返回值,这个方法就不会执行
         * 其实这个监听类,监听的是IBinder
         * @param name
         * @param service
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            musicBind = (CustomService.MusicBind)service;
        }

        /**
         * 当失去连接的时候调用
         * @param name
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
  1. 创建一个按钮调用服务中的方法
 /**
     * 操作音乐的方法,
     * @param view
     */
    public void operateMusic(View view){
        musicBind.startMusicBind();
        musicBind.stopMusicBind();
        musicBind.previousMusicBind();
        musicBind.nextMusicBind();
    }

通过接口调用服务中的方法

通过接口操作服务中的任务

这时候可能你会有点疑问,直接创建服务对象调用服务方法不行吗?可以但是有个问题,这样使用,那这个服务类就和普通的类没区别了,就不处在服务的环境中了,也就是服务中的上下文(Context)就不能使用了,只能通过参数传递了,还有一些其他问题,所以正确的使用方式,还是在服务监听中通过IBinder来传递参数,调用方法。
还有一个方式可以操作服务中的方法,还是通过监听,不过这时监听中接收的就不是用CustomService.MusicBind这个内部类接收,而是用一个接口接收。

  1. 定义一个接口
public interface IMusicService {
     void startMusicBind();
     void stopMusicBind();
}
  1. 自定义服务中的Bind类实现这个接口
    private class MusicBind extends Binder implements IMusicService{}
  2. 监听接收这个接口
    这一步就是java语言特性,多态的使用。
    musicBind = (IMusicService)service;
  3. 把接收到的接口提到Activity中调用
    musicBind.startMusicBind();
    musicBind.stopMusicBind();
    这样加一层封装,算是面向接口编程。

开启一个长期运行,同时可操作的服务

还有一个疑问就是播放音乐这个功能,既是长期运行,又是可以操作的,所以应该如何实现呢?
其实挺简单的,先调用startService然后调用bindService。这样就实现了退出应用,还能操作服务中的任务。

        Intent intent = new Intent(this, CustomService.class);
        startService(intent);
        //第一个参数是意图
        //第二个参数是监听服务连接的
        //第三个是标记,BIND_AUTO_CREATE就是自动连接到服务
        myServiceConnection = new MyServiceConnection();
        bindService(intent,myServiceConnection,BIND_AUTO_CREATE);

一般这种情况开启服务就可以了,不用主动关闭。但是不关闭就会报一个leak的问题,不是异常,就是谷歌打印的一个提醒。解决方案就是在页面销毁的时候解绑服务,但是并不是真的解绑,只是不打印日志了。

   @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(myServiceConnection);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值