Service 服务

Service: 长期在后台运行没有界面的进程.

  • 应用场景
  1. 监视一个硬件是否被插入
  2. 连接服务器刷新最新的数据
  3. 定时对的轮询

注意: 服务是运行在主线程中的,所以不能再服务中进行耗时操作,可以在服务中创建子线程进行耗时操作.

进程的优先级
  • Foreground process

前台进程: 用户正在操作的应用程序所在的进程就是前台进程

  • Visible process

可视进程: 用户已经不能操作这个应用程序了,但是界面用户仍然可以看到

  • Service process

服务进程: 应用程序有一个服务代码正在运行

  • Background process

后台进程: 应用程序有界面,但是界面被用户最小化(home)

  • Empty process

空进程: 应用程序没有任何运行的Activity,service.

优先级(系统会优先回收优先级较低的进程):

前台进程>可视进程>服务进程>后台进程>空进程

服务的生命周期
  • onCreate()--startService()开启服务,服务只会被创建一次,在创建的时候调用onCreate(),一旦服务创建完毕,再去开启服务也不会执行此方法,只会执行onstart(过时)和onstartcommand()
  • onstart(过时),onstartcommand()
  • onDestory()--stopService()停止服务,服务只会被停止一次

代码:

1.创建对应的服务类继承Service 2.在清单文件中注册

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

2.在需要的位置开启或关闭服务

/**
     * 开启服务
     */
    private void start() {
        Intent intent = new Intent(this, DemoService.class);
        startService(intent);
    }
    
     /**
     * 关闭服务
     */
    private void stop() {
        Log.e(TAG, "stop: 点击停止" );
        Intent intent = new Intent(this, DemoService.class);
        stopService(intent);

    }
绑定服务调用服务方法的步骤

虽然可以用startService()开启服务,但是不可以与服务进行通讯,所以使用bindService()可以间接调用服务里面对的方法,与服务进行通讯.

  • 步骤
  1. 定义服务,并在清单文件中注册
public class TestService extends Service{

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

  1. 在服务内定义一个代理人对象MyBinder,在内部定义一个方法,可以调用服务内部方法(为了隐藏服务内部的实现细节,只对外暴露对应的方法,定义一个接口类IService )
public interface IService {
      void callMethodInService(String name);
   }
public class MyBinder extends Binder implements IService {
        //调用服务的内部方法,将来间接与外部进行通讯
        @Override
        public void callMethodInService(String name) {
            //自定义的服务内部的方法
            methonInService(name);
        }
    }


  1. 在服务实现的Onbind()方法中,将这个代理对象返回.

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

  1. 在activity中采用绑定的方式连接服务--bindService()
/**
     * 绑定服务
     */
    private void bind() {
        Intent intent = new Intent(this, TestService.class);
        //绑定服务
        //new Conn() 通讯频道 
        //BIND_AUTO_CREATE 如果服务不存在,会把服务创建出来
        bindService(intent, new Conn(), BIND_AUTO_CREATE);

    }

5.定义bindService()中"通讯频道"这个内部类(new Conn())实现其中的方法

private class Conn implements ServiceConnection {
        //当服务连接成功调用的方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
              //private IService mService;
              mService = (IService) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

6.强制类型转换

mService = (IService) service;

7.调用代理人对象的方法--间接调用了服务里面的方法.

/**
     * 调用服务里面的方法
     */
    private void method() {
        //callMethodInService 服务的中方法
        mService.callMethodInService("阿彪");
    }
//解绑服务
unbindService(conn);
绑定方式开启服务的生命周期
  • 绑定的方式开启服务oncreate->onbind
  • 服务的onstart和onstartcommand不会执行
  • 解除绑定 unbind-->ondestory
  • 多次绑定服务,服务只会创建一次,oncreate只会执行一次
  • 多次绑定服务onbind只会执行一次
  • 在实际开发中如果需要调用服务中的方式,使用绑定的方式开启服务,只能绑定一次
  • 服务只能解绑一次,如果用同一个conn对象对象多次解绑,会抛出异常
两种开启服务方式的比较
  • start开启服务

服务一旦开启,长期在后台运行不会随着activity的销毁而停止服务,开启者activity不能调用服务里面玩的方法.

  • bind的方式开启服务

如果activity退出了,服务也会跟着停止 开启者(activity)可以间接的调用服务里面的方法

  • 混合的方式开启服务

应用场景:为了保证服务仅能长期在后台运行,又能调用服务里面的方法,可以使用混合开启服务的方式,但是因为服务被开启后同时又被绑定,必须要先解除绑定,才能停止服务,因此要想混合开启服务必严格按照以下步骤编写代码:

  1. start方式开启服务(保证服务长期在后台运行)
  2. bind的方式绑定服务(为了调用服务的方法)
  3. unbind的方式解除绑定
  4. stop 的方式停止服务
本地服务和远程服务
  • 本地服务 local service

服务的代码在当前应用程序的内部

  • 远程服务 romote service

服务在另一个应用程序里面

进程

进程是操作系统分配的一块独立的内存空间,因此一个程序想要间接调用另一个程序里面的服务的方法,需要进行进程间对的通讯(IPC inter process communication),那么就需要用到aidl(安卓接口定义语言 android interface definition language)来实现进程间对的通讯.

绑定远程服务调用远程服务方法的流程

大致根本地服务的代码是一样的

  1. 远程服务的接口文件.java-->.aidl
  2. 把接口定义文件的修饰符删除 public private
  3. 原来代理人MyBinder extend Binder implemet IService--> extends ISer vice.Stub
  4. 先把远程服务.aidl文件拷贝到本地应用程序的工程目录里面,包名一致
  5. iService = IService.Stub.asInterface(service);得到远程服务的代理对象
  6. 通过代理对象调用远程服务的方法.
  • 代码

---创建一个被调用的服务工程

1. 定义服务,并在清单文件中注册,并设置对应的action public class MyService extends Service{ } //添加属性android:exported="true" <service and

roid:name=".MyService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.alipay" />
            </intent-filter>
        </service>
  1. 创建aidl接口文件 android studio中工程项目 " 右键-->AIDL-->AIDL file" 创建aidl文件 ITestService.aidl
interface ITestService {
       int callTestMethodInService(String name);
    }

3.在服务中创建对应的代理人对象,并间接调用服务中的方法

//代理人对象
    private class MyBind extends ITestService.Stub {
        @Override
        public int callTestMethodInService(String name) {
            //调用服务的方法
            return methodInService(name);
        }
    }

    /**
     * 服务中的方法
     */
    private int methodInService(String name) {
        return name.length();
    }

--在另外一个项目中调用服务中的方法

  1. 绑定服务
private void bind() {
        Intent intent = new Intent();
        // 需要制定action和对应服务的包名,否则会报错
        intent.setAction("com.example.alipay");
        intent.setPackage("com.example.alipay");
        bindService(intent, new Conn(), BIND_AUTO_CREATE);
    }
5.将服务中的aidl文件拷贝过来,包名一定要一致!!!,然后build一下工程! 6.创建对应的"通讯频道 conn"
private class Conn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //IService的aidl创建完成之后刷build一下工程
            iTestService = ITestService.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

7.强制类型转换

iTestService = ITestService.Stub.asInterface(service);

8.调用服务的方法

private void method() {
        try {
            int hahahah = iTestService.callTestMethodInService("hahahah");
            Log.e(TAG, "method: " + hahahah);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }