Android组件

Service

2017-07-11  本文已影响0人  沅兮

Service介绍

进程优先级

空 进 程
后台进程
可见进程
前台进程

服务的启动与停止

启动服务
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 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")

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

AIDL:Android interface definition language 安卓接口定义语言
实现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) {
            
    }
}
上一篇 下一篇

猜你喜欢

热点阅读