Service

1.基本概念

Service 是应用组件之一,用来执行需要长时间运行的操作,Service 运行在后台并且跟用户没有交互界面。

其他应用的组件可以启动一个Service,一旦启动起来,该Service就一直在后台运行,就算用户已经将该应用置为后台进程。

其他应用的组件也可以通过绑定的形式跟一个Service进行交互,甚至完成进程间通信
  • Service的特点
1.Service 在Android中是一种长生命周期的组件,它不实现任何用户界面,是一个没有界面的Activity
2.Service 长期在后台运行,执行不关乎界面的一些操作比如:网易新闻服务,每隔1分钟去服务查看是否有最新新闻
3.Service 和Thread 有点相似,但是使用Thread 不安全,不严谨
4.Service 和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的操作

2.Android中的进程

  • 在Android 中进程优先级由高到低,依次分为:
1.Foreground process(前台进程)
2.Visible process(可见进程)
3.Service process(服务进程)
4.Background process(后台进程)
5.Empty process(空进程)
  • 进程的回收机制
进程的回收顺序是:从低到高
1.当系统内存不够用时, 会把空进程一个一个回收掉
2.当系统回收所有的完空进程不够用时, 继续向上回收后台进程, 依次类推
3.面对服务进程、可视进程、前台进程时, 系统非必要情况下不会轻易回收
4.如果需要回收以上三种进程,在系统内存够用时,会再重新启动进程;但是服务进程如果用户手动的关闭服务, 这时服务不会再重启了

3. 使用service

1.服务是运行在后台的进程,跟我们熟悉的Thread很像
2.在使用Service 时一定要注意,Service默认运行在应用的主线程中,因此如果你需要在Service 中执行大量的或者阻塞(比如网络访问、IO等)的任务,那么依然需要在Service 中开启一个Thread 来完成这些工作
3.使用Service并不影响使用Thread,而且很多情形下,我们都是在Service中开启子Thread的混合使用方式

4.Code

  • 自定义Service
/**
 * 后台的服务 ,用来窃听电话
 */
public class PhoneService extends Service {
    
    private TelephonyManager tm;//电话管理器
    private MyPhoneListener listener;//监听器
    private MediaRecorder mRecorder;//录音器
    
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    //创建服务时
    public void onCreate() {
        //获取电话管理器
        tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        listener = new MyPhoneListener();
        //注册电话状态的监听器
        tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
    }
    
    //自定义电话监听器
    private class MyPhoneListener extends PhoneStateListener {
    
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
                // 空闲状态,代表当前没有电话
                case TelephonyManager.CALL_STATE_IDLE: 
                    if(mRecorder!=null){
                        System.out.println("停止录音");
                        stopRecording();//停止录音方法
                    }
                    break;
                // 响铃状态
                case TelephonyManager.CALL_STATE_RINGING:
                break;
                // 通话状态
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    System.out.println("通话状态,开启录音机,录音.");
                    startRecording();//开始录音方法
                break;
            }
        }
    }
    
    //销毁服务时
    public void onDestroy() {
        //注销电话状态的监听
        tm.listen(listener, PhoneStateListener.LISTEN_NONE);
        super.onDestroy();
    }
    
    //开始录音的方法
    private void startRecording() {
        mRecorder = new MediaRecorder();
        //设置声音来源,从麦克风录音
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //设置输出格式为3gp 
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        //设置输出到的文件
        mRecorder.setOutputFile("/mnt/sdcard/"+SystemClock.uptimeMillis()+".3gp");
        //设置输出的音频编码
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        try {
            mRecorder.prepare();//录音器准备
        } catch (Exception e) {
            System.out.println("prepare() failed");
        }
        mRecorder.start();//开启
    }
    
    //停止录音的方法
    private void stopRecording() {
        mRecorder.stop();
        //释放录音器资源
        mRecorder.release();
        mRecorder = null;
    }
}
  • 启动Service
startService 或 bindService两种启动方式
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void start(View view){
        //创建一个Intent 对象
        Intent intent = new Intent(this,PhoneService.class);
        //启动服务
        startService(intent);
    }
}
  • AndroidManifest.xml中注册
//保存录音文件到sdcard、监听电话状态、录音都需要添加权限
<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"/>

//注册Service:
<service android:name="com.demo.phonelistener.PhoneService" >
</service>

5.Service的生命周期

  • Service有生命周期,Service的生命周期,从它被创建开始,到它被销毁为止,可以有两条不同的路径:标准开启模式和绑定模式

  • started service(标准开启模式)

1.被开启的service 通过其他组件调用startService()被创建
2.这种service 可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它
3.当service 被停止时,系统会销毁它
  • bound service(绑定模式)
1.被绑定的service是当其他组件(一个客户)调用bindService()来创建的
2.客户可以通过一个IBinder接口和service 进行通信
3.客户可以通过unbindService()方法来关闭这种连接
4.一个service 可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service
  • 任何Service 都潜在地允许被绑定
  • 一个被开启的Service仍然可能被绑定

6.AIDL实现进程间通信

1.Android 采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信
2.Android 通过接口定义语言(Android Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码
3.AIDL 是Android 的一种接口描述语言,编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的
  • aidl的使用步骤

  • service端

//1.远程服务定义的接口文件不能是.java文件,需要改成.aidl文件,里面的修饰符都不需要

package com.demo.remote;

interface IService {
    void callMethodInService();
}

//2.程序会自动在gen目录下生成Iservice.java文件,会有一个抽象的静态类Stub继承了Binder对象并实现了IService接口

//3.创建服务,在服务中创建中间代理人对象,在onBind()方法中返回出去给绑定该服务的对象使用。

public class RemoteService extends Service {
    /**中间代理人*/
    private class MyBinder extends IService.Stub{
        public void callMethodInService() {
            //调用服务里面的方法
            methodInService();
        }
    }

    public IBinder onBind(Intent intent) {
        //返回中间代理人
        return new MyBinder();
    }
    
    public void onCreate() {
        System.out.println("远程服务被创建了...");
        super.onCreate();
    }
    
    public void onDestroy() {
        System.out.println("远程服务被销毁了...");
        super.onDestroy();
    }
    
    //服务里面的方法
    public void methodInService(){
        System.out.println("我是远程服务的方法,我被调用了....");
    }
}
  • 调用者端
public class MainActivity extends Activity {
    private MyConn conn;
    private IService iService;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void bind(View view){
        Intent intent = new Intent();
        //调用远程服务 :隐式意图
        intent.setAction("com.demo.remote");
        conn = new MyConn();
        bindService(intent, conn, BIND_AUTO_CREATE);
    }
    
    private class MyConn implements ServiceConnection{
        public void onServiceConnected(ComponentName name, IBinder service) {
            //得到远程服务的代理对象
            iService = IService.Stub.asInterface(service);
        }
        public void onServiceDisconnected(ComponentName name) {
        }
    }
    
    public void call(View view){
        try {
            //通过代理对象调用远程服务的方法
            iService.callMethodInService();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容