Service

作者: 沅兮 | 来源:发表于2017-07-11 14:52 被阅读0次

Service介绍

  • 运行于后台,没有前台界面的组件,用于运行需要在后台运行的代码。
  • 在Activity中开启线程下载数据,下载代码是在Activity中的。当点击返回键退出app时,如果内存充足,进程依然存在,那么下载代码会运行下去直到下载完毕;如果内存不足,进程会被杀死,线程自然而然会停止,下载也就中断了,故要将下载代码,播放音视频代码放在服务当中。

进程优先级

空 进 程
  • 没有任何活动的应用组件(Activity和Service,Receiver常驻内存,但是被删了等有广播来时,依然会再次启动,provider不常驻内存)
后台进程
  • 拥有一个对于用户不可见的Activity(onStop()调用时)
    服务进程:拥有一个通过startService启动的服务(下载操作在这里,如果内存不足,会被杀死,如果内存又变得充足,服务会继续启动)
可见进程
  • 拥有一个不在前台但是对用于依然可见的Activity(onPause()调用时)
  • 拥有一个与可见activity绑定的服务(此服务如果为本地服务,那么(1)肯定满足;如果此服务为远程服务,那么本地绑定远程服务,本地的activity可见,远程服务的activity不可见,按道理来说,远程的服务为后台进程或空进程,其实不是,应该为可见进程,满足(2)的定义)
前台进程
  • 拥有一个正在于用户交互的activity(onResume()调用时)
  • 拥有一个与正在于用户交互的activity绑定的服务(远程服务为前台进程)
  • 拥有一个运行在前台的服务(服务调用了startForeground())
  • 拥有一个正在执行其中一个生命周期方法的服务(onCreate()、onStart()、onDestroy(),提高其短暂的优先级用来保证不被杀死)
  • 拥有一个正在onReceiver方法的广播接收者(短暂提高保证优先级)

服务的启动与停止

启动服务
public void start(){
    Intent intent = new Intent(this,MyService.class);
    startService(intent);
}
停止服务
public void stop(){
    Intent intent = new Intent(this,MyService.class);
    startService(intent);
}~~~

##### 自定义服务

public class MyService extends Service{

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

}



# startService的生命周期

第一次调用startService:onCreate() - onStartCommand() - onDestory()

多次调用只会多次调用onStartCommand(),onCreate()只会调用一次

多次调用startServie:onCreate() - onStartCommand() - ... - onStartCommand() - onDestory()

public class MyService extends Service{

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

 * 此方法被废弃:Activity中onStart()方法表示界面可见,但是没有焦点,所以服务中这个方法不适合
@Override
@Deprecated
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
}

 * 此方法完全代替onStart(),内部调用onStart()方法
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
     *** onStartCommand()使用时,返回的是一个int整型,这个整型有四个返回值:
      * START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的
         intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一
         定会调用onStartCommand(Intent,int,int)方法。如果再次期间没有任何启动命令被传到service,
         那么参数Intent将为null.
      * START_TO_STICKY:"非粘性的".使用这个返回值时,如果在执行完onStartCommand()后,服务被
         异常kill掉,系统不会自动重启该服务.
      * START_REDELIVER_INTENT:重传Intent.使用这个返回值时,如果在执行完onStartCommand()后,
         服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入.
      * STATE_STICKY_COMPATIBILITY:start_sticky的兼容版本,但不保证服务被kill后一定能重启.
    return super.onStartCommand(intent, flags, startId);
}

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

}~~~

实例一:电话录音机

### 添加权限 
 * 读取通话状态权限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 * 写内存卡权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 * 录音权限
<uses-permission android:name="android.permission.RECORD_AUDIO" />

public class MyService extends Service {

    private MediaRecorder recorder;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
         * Actvity和Service都是Context的子类,可直接使用方法
        TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
         * 监听通话状态
         * arg0:监听通话的listen,不是接口的原因是方法太多
         * arg1:即时不实现方法,但是其他的回调依然存在,所以此方法控制只回调哪些方法
        tm.listen(new PhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);
    }

    class PhoneListener extends PhoneStateListener {
         * 监听通话状态改变,电话状态:空闲、响铃、摘机
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
             * 空闲
            case TelephonyManager.CALL_STATE_IDLE:
                if(recorder != null){
                    System.out.println("停止录音");
                    //停止录音
                    recorder.stop();
                    //释放录音机占用的资源
                    recorder.release();
                    recorder = null;
                }
                break;
             * 响铃
            case TelephonyManager.CALL_STATE_RINGING:
                if(recorder == null){
                    recorder = new MediaRecorder();
                     * 设置音频来源
                    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                     * 设置输出格式
                    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                    recorder.setOutputFile("sdcard/voice.3gp");
                     * 设置音频编码
                    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                    try {
                        System.out.println("准备好");
                        recorder.prepare();
                    } catch (IllegalStateException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
                * 摘机
            case TelephonyManager.CALL_STATE_OFFHOOK:
                if(recorder != null){
                    System.out.println("开始录音");
                    recorder.start();
                }
                break;
            }
        }
    }
}~~~

# 服务的绑定与解绑

public class TestActivity extends Activity {

private MyBindConnection conn;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    conn = new MyBindConnection();
}

public void bind(){
    Intent intent = new Intent(this,MyBindService.class);
    bindService(intent, conn, BIND_AUTO_CREATE);
}

public void unBind(){
    unbindService(conn);
}

class MyBindConnection implements ServiceConnection{
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        * 服务建立连接并且service中onBind()有返回值时此方法才会调用
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
        * 服务的连接被异常中断时调用,unbind()调用时不调用此回调方法,因为是正常中断
    }
}

}~~~

绑定服务的生命周期

public class MyBindService extends Service{
    
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}~~~

# startService和bindService的区别
##### startService
- 通过startService启动的服务,该服务所在的进程会变成服务进程。
- 服务与启动它的Activity不再有任何联系。

##### bindService
- 通过bindService绑定的服务,进程优先级不变。与APP的进程保持一样。
- 绑定的服务与启动它的Activity是同生共死的,Activity销毁了,服务也要销毁,不过服务销毁了,Activity不会销毁。因此,绑定服务是不能做下载操作的。

#####为什么需要bindService?
- 在service中如果有一个方法,那么通过startService则无法调用此方法,因为通过startService启动的服务是没有返回对象的,因而产生了一个bindService。

# 调用bindService中方法的一般逻辑
  • 对公的牵线业务
    public interface PublicWork {
    void qianxian();
    }

public class BossService extends Service{
@Override
public IBinder onBind(Intent intent) {
* 返回一个工作者对象
return new Worker();
}

 * onBind()需要返回一个IBinder对象,因此Worker类需要实现IBinder接口
 * IBinder接口中方法很多,而Binder是IBinder的实现类,因此去继承Binder即可
 * 实现对公业务的接口,避免暴露了自己私有的方法
class Worker extends Binder implements PublicWork{
    
     * 对公的业务
    @Override
    public void qianxian(){
         * 中间人的方法去实现Service的方法,然后在Activity中调用中间人的方法
        banzheng();
    }
    
     * 中间人的私有业务
    public void privateWork(){}
}

 * Boss服务中有一个办证的方法
public void banzheng(){
    System.out.println("办证成功");
}

}

public class TestActivity extends Activity {

 * 中间人
private Worker worker;
 * 对公业务类
private PublicWork publicWork;
private MyBindConnection conn;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    conn = new MyBindConnection();
}

public void bind(){
    Intent intent = new Intent(this,BossService.class);
    bindService(intent, conn, BIND_AUTO_CREATE);
}

public void unBind(){
    unbindService(conn);
}

class MyBindConnection implements ServiceConnection{
     * service就是onBind()返回的中间人
     * 服务建立连接并且service中onBind()有返回值时此方法才会调用
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
         * 1.获取中间人的实例
        worker = (Worker) service;
         * 2.获取中间人的对公业务
        publicWork = (PublicWork) service;
    }
    
     * 服务的连接被异常中断时调用,unbind()调用时不调用此回调方法,因为是正常中断
    @Override
    public void onServiceDisconnected(ComponentName name) {
        
    }
}

 * 调用中间人的方法来实现服务自己的方法
public void click(){
     * 如果使用中间人的类,则会暴露中间人的私有方法
    worker.qianxian();
    worker.privateWork();
     * 通过接口来避免中间人的所有方法被调用
    publicWork.qianxian();
     * 对公的类不可调用中间人的私有方法
    publicWork.privateWork();
}

}~~~

实例二:模拟音乐播放器 -- 混合启动服务

public interface ControllerInterface {
    void play();
    void pause();
}
public class MusicService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return new MusicController();
    }
    
    class MusicController extends Binder implements ControllerInterface{
        @Override
        public void play() {
            MusicService.this.play();
        }
        @Override
        public void pause() {
            MusicService.this.pause();
        }
    }
    
    public void play(){
        System.out.println("音乐在播放");
    }
    
    public void pause(){
        System.out.println("音乐已暂停");
    }
}
public class MusicActivity extends Activity{
    
    private ControllerInterface controller;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(this,MusicService.class);
         * service的混合启动,让Music拥有startService和bindService的共同特点
         * 混合启动的生命周期为:onCreate - onStart() - onBind() - onUnBind() - onDestory()
        startService(intent);
        bindService(intent, new ServiceConnection() {
            
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                controller = (ControllerInterface) service;
            }
            
            @Override
            public void onServiceDisconnected(ComponentName name) {
                
            }                       
        }, BIND_AUTO_CREATE);
    }
    
    public void playClick(){
        controller.play();
    }
    
    public void pauseClick(){
        controller.pause();
    }
}~~~

# 启动远程服务
- 启动自己项目中的Servie叫做本地服务;启动另外一个项目中的Service叫做远程服务。
- 启动远程服务需要使用隐式启动,使用setAction("a.b.c")
  • 远程服务需要指定action
    <service android:name=".RemoteService">
    <intent-filter>
    <action android:name="a.b.c">
    </intent-filter>
    </Service>
  • 启动远程服务
    Intent intent = new Intent();
    intent.setAction("a.b.c");
    startService(intent);~~~

远程服务之进程间通信(AIDL)

AIDL:Android interface definition language 安卓接口定义语言
实现AIDL的详细步骤:
  • 将远程服务中接口文件的后缀名 .java改为 .aidl,这时在gen目录中自动生成 .java文件
  • 远程服务中aidl文件中所有的东西都是public,不能自己定义访问修饰符。
  • 远程服务中中间人对象只需要继承Stub即可,这个Stub对象已经继承了Binder并实现了PublickBusiness接口。
  • 本地服务中,新建一个与远程服务中aidl的所在包一样的包,然后将这个aidl文件复制到这个包下。(aidl的包名不能改变)。
  • 本地服务中用新方式进行强转。
class MyBindConnection implements ServiceConnection{
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
            publicWork = (PublicWork) service;
             * 使用新方式强转
            publicWork = Stub.asInterface(service);
        }
        
    @Override
    public void onServiceDisconnected(ComponentName name) {
            
    }
}

相关文章

网友评论

    本文标题:Service

    本文链接:https://www.haomeiwen.com/subject/dacmhxtx.html