安卓基础第八天(四大组件之Service,AIDL)

Service简介

  • 是一种长生命周期的组件,是一个没有界面的组件,由其他组件开启
  • 长期在后台运行, 执行不关乎界面的一些操作
  • 和Thread 有点相似,但是使用Thread 不安全, 不严谨
  • 运行在主线程中,不能用它来做耗时的操作

Android进程的概念介绍

进程优先级由高到低,依次为:
1. Foreground process 前台进程
用户正在交互 可以理解成相 当于 Activity执行onResume方法
2. Visible process 可视进程
用户没有在交互 但用户还一直能看得见页面 相当于Activity执行了onPause方法
3. Service Process 服务进程
通过startService()开启了一个服务
4. Background process 后台进程
当前用户看不见页面 相当于Activity执行了onStop方法
5. Empty process 空进程
进程的回收顺序是:从低到高,前台这三种进程时, 系统非必要情况下不会轻易回收

Service的生命周期

服务有两种开启方式,一个是直接onstart,另一个是绑定服务。

started service(标准开启模式)

  1. 服务通过startservice方式开启,第一次开启服务,会执行服务的onCreate 和 onStart方法
  2. 如果第二次开启服务,执行onStrat方法
  3. 服务被开启后,会在设置页面的running里面找得到这个服务
  4. startservice 开启服务 ,服务就会在后台长期运行,直到用户手工停止或者调用StopService方法,服务才会被销毁

bindService(绑定模式)

为什么要引入bindservice的API?
为了调用服务中的业务逻辑方法
特点:
1. 当第一次开启服务,会执行服务的onCreate方法 和 onBind()方法
2. onBind() 只执行一次,再次绑定,onBind ()不会执行
3. 通过绑定方式开启的服务,调用者(activity) 退出销毁,服务也会跟着退出
4. 通过bind方式开启服务 服务不能再设置页面里面找到 相当于是一个隐形的服务
5. bindservice不能多次解绑,多次解绑会报错

PS:如果一个程序的调用者(activity )绑定了服务,那么这个activity 退出时,会报异常,
xxx has leaked ServiceConnection xxx that was originally bound here
说是服务没有被释放。那么我们可以重写activity 的onDestory 方法,方法内调用unbindService(),显示的解除与服务的绑定。

生命周期图

Service 的这两种生命周期并不是完全分开的。
2种调用方式生命周期图
既想让服务在后台长期运行,又想调用服务里面的方法,可以使用混合嵌套方式开启服务
1. 先调用startService()方法,保证服务在后台长期运行
2. 调用bindservice()目的获取我们定义的中间人对象(IBind对象),调用服务里面的方法
3. 这时如果调用unbindservice() 服务就不会销毁
4. 最后可以调用stopservice() 停止服务

示例 通话监控

清单配置

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

        <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" />

        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.itheima.phonelistener.MainActivity"
            android:label="@string/app_name" >

        </activity>


        <!--配置广播接收者  -->

        <receiver android:name="com.itheima.phonelistener.BootReceiver">

            <intent-filter >

                <action android:name="android.intent.action.BOOT_COMPLETED"/>

            </intent-filter>

        </receiver>


          <service android:name="com.itheima.phonelistener.PhoneService"></service>
    </application>

代码
系统启动广播接收者开启服务

public class BootReceiver extends BroadcastReceiver {

    //当手机重启后 会执行该方法 
    @Override
    public void onReceive(Context context, Intent intent) {
        //就把开启服务的逻辑 放到 这个方法里 
        Intent intent1 = new Intent(context,PhoneService.class);
        //开启服务 
        context.startService(intent1);
    }
}

服务

public class PhoneService extends Service {


    private MediaRecorder recorder;
    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    //服务第一次被开启的时候调用
    @Override
    public void onCreate() {

        //[1]获取电话管理者的实例  
        TelephonyManager tm  = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

        //[2]注册一个电话状态的监听
        tm.listen(new MyPhoneStateListenrer(), PhoneStateListener.LISTEN_CALL_STATE);


        super.onCreate();
    }


    //监听电话的状态
    private class MyPhoneStateListenrer extends PhoneStateListener{
        //当设备的状态发生改变的时候调用


        @Override
        public void onCallStateChanged(int state, String incomingNumber) {

            //[3]具体判断一下  电话是处于什么状态
            switch (state) {
            case TelephonyManager.CALL_STATE_IDLE:  //空闲状态
                if (recorder!=null) {
                     recorder.stop();  //停止录
                     recorder.reset();   // You can reuse the object by going back to setAudioSource() step
                     recorder.release(); // Now the object cannot be reused
                }           
                break;

            case TelephonyManager.CALL_STATE_OFFHOOK://接听状态 

                System.out.println("开始录");
                //开启录
                 recorder.start();   // Recording is now started

                break;

            case TelephonyManager.CALL_STATE_RINGING:  //响铃状态

                System.out.println("我准备一个录音机出来 ");

                //[1]获取MediaRecorder类的实例
                recorder = new MediaRecorder();
                //[2]设置音频的来源
                 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //zet 
                 //[3]设置音频的输出格式 
                 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 //[4]设置音频的编码方式 
                 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                 //[5]保存的文件路径
                 recorder.setOutputFile("/mnt/sdcard/luyin.3gp");
                 //[5]准备录音
                 try {
                    recorder.prepare();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
            }

            super.onCallStateChanged(state, incomingNumber);
        }

    }

    //当服务销毁的时候执行 
    @Override
    public void onDestroy() 绍绍绍绍绍


        super.onDestroy();
    }

}

Android InterfaceDefinition Language

为了实现进程之间的相互通信,
Android 采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信,
并且Android 通过接口定义语言(Android InterfaceDefinition Language ,AIDL)来生成两个进程之间相互访问的代码

总结

示例 使用AIDL本地调用其他远程()进程方法

当前应用

public class MainActivity extends Activity {

    private MyConn conn;


    private Iservice iservice; //是我们的中间人对象 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //[1]调用bindservice 获取我们定义的中间人对象 

        Intent intent = new Intent();
        //设置一个action
        intent.setAction("com.itheima.remoteservice");
        conn = new MyConn();
        //[2]目的是为了获取我们定义的中间人对象
        bindService(intent, conn,BIND_AUTO_CREATE); 
    }

    //点击按钮 调用远程应用程序服务里面的方法
    public void click(View v) {
        try {
            iservice.callTestMethod();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    //当Activity销毁的时候调用
    @Override
    protected void onDestroy() {  
        //当Activity销毁的时候  取消绑定服务
        unbindService(conn);
        super.onDestroy();
    }

    //监视服务的状态
    private class MyConn implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {           
            //获取中间人对象 
        iservice = Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }   
    }   
}

一份同包名下的远程AIDL文件

远程应用服务

//远程服务
public class RemoteService extends Service {

    //[2]把我们定义的中间人对象返回
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    //在服务里面定义一个方法

    public void testMethod(){
        System.out.println("我是远程服务里面的方法");
    }

    //[1]定义中间人对象 
    private class MyBinder extends Stub{

        //调用testMethod方法
        @Override
        public void callTestMethod() {

            testMethod();
        }
    }
}

AIDL文件

interface Iservice {

    //把想暴露的方法暴露出来
     void callTestMethod();
}

猜你喜欢

转载自blog.csdn.net/opopopwqwqwq/article/details/79345918
今日推荐