[安卓基础]学习第八天

一、进程概念介绍

安卓的四大组件,都是运行在主线程的,不能运行耗时操作,否则ANR

1-1.进程优先级

1. Foreground process 【前台进程】
    优先级最高,相当于Activity执行了onResume(),用户正在交互

2. Visible process 【可视进程】
    一直影响用户看得见,相当于Activity执行了onPause()

3. Service process 【服务进程】
    服务进程在后台运行,没有界面,通过startService()开启了一个服务

4. Background process 【后台进程】
    用户不可见,相当于Activity执行了onStop(),但是Activity并没有销毁

5. Empty process 【空进程】
    不会维持任何组件运行

二、start方式开启服务的特点

2-1.新建一个服务的过程

  1. 新建一个类,继承service
public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    // Called by the system when the service is first created. Do not call this method directly.
    // 当服务第一次创建的时候调用
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
    }

    // 当服务启动的时候调用
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        return super.onStartCommand(intent, flags, startId);
    }

    //当服务销毁时调用
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

}
  1. 修改清单文件如下
    <application
        ....
        <service android:name="com.elnui.day08_servicedemo.MyService">

        </service>
    </application>

2-2.开启和关闭服务

    public void click1(View v){
        Intent intent = new Intent(this,MyService.class);
            startService(intent);
    }

    public void click2(View v){
        Intent intent = new Intent(this,MyService.class);
        stopService(intent);
    }

2-3.特点

  • 第一次开启服务,服务执行onCreat()和onStartCommand()
  • 第二次开启服务,服务只执行onStartCommand()
  • ==当服务开启后,就会在后台长期运,直到用户手工停止==

三、电话窃听器案例

3-1.新的API

1. SmsManage

2. TelephonyManager

- 拿到实例不能直接new,要使用 Context.getSystemService(Context.TELEPHONY_SERVICE)拿到

3-2.实现步骤

  1. 定义一个服务,开启服务,记得在清单文件添加service节点
  2. 在服务里onCreat()里获取TelephonyManager的实例
TelephonyManager TELManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
  1. 注册电话的监听
TELManager.listen(new MyPhoneListener(), PhoneStateListener.LISTEN_CALL_STATE);
  1. 定义一个类监听电话的状态
    private class MyPhoneListener extends PhoneStateListener{
        // 当电话设备的状态发生改变时调用
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            // TODO Auto-generated method stub

            // 判断电话的状态
            switch(state){
            case TelephonyManager.CALL_STATE_IDLE:      // 空闲状态
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:   // 接听状态
                break;
            case TelephonyManager.CALL_STATE_RINGING:   // 响铃状态
                System.out.println("___准备录音机");
                break;
            }
            super.onCallStateChanged(state, incomingNumber);
        }
    }

3-3.实现录音,MediaRecorder

        //准备录音机

        mRecorder = new MediaRecorder();

        // 设置音频的来源
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);    // 此处模拟器只能一MIC,单向的
        // 设置输出的格式
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        // 设置存放的路径 
        mRecorder.setOutputFile("/mnt/sdcard/luyin.3gp");
        // 设置音频的编码方式
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
            mRecorder.prepare();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
// 开启录音
mRecorder.start();
    // 如果在空闲状态
    if(mRecorder != null){
        mRecorder.stop();
        mRecorder.reset();
        mRecorder.release();
    }

3-4.把开启服务的代码放到广播中

public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent intent1 = new Intent(context,LisenerService.class);

        context.startService(intent);
    }

}

四、使用服务注册特殊的广播接收者

操作特别频繁的广播事件,比如屏幕的解锁和加锁

4-1.实现步骤

[service]作用:管理广播接收者

public class BroadcastReceiverService extends Service {
    private ScreenReceiver receiver;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        // 创建ScreenReceiver实例
        receiver = new ScreenReceiver();
        // 获取IntentFilter实例,目的添加Action
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.SCREEN_OFF");
        filter.addAction("android.intent.action.SCREEN_ON");
        // 动态注册Action
        registerReceiver(receiver, filter);
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        // 当服务关闭时,取消注册广播接收者
        unregisterReceiver(receiver);
        super.onDestroy();
    }
}

[开启服务]

    Intent intent = new Intent(this,BroadcastReceiverService.class);
    startService(intent);

[清单配置服务]

<service android:name="com.elnui.day08_flubroadcastreceiver.BroadcastReceiverService" >
</service>

五、bingService开启服务特点

5-1.bindService()

boolean android.content.ContextWrapper.bindService(Intent service, ServiceConnection conn, int flags)

5-2.代码实现

public void click3(View v){
        Intent intent = new Intent(this,MyService.class);
        conn = new MyConn();
        bindService(intent, conn,  BIND_AUTO_CREATE);
    }

    // 定义一个类监视服务的状态
    /*
     *  当onBind返回null的时候这个方法不会被调用
     * */
    private class MyConn implements ServiceConnection{

        // 当服务连接成功时调用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            System.out.println("__bindService's connected success!!");
        }

        // 失去连接时调用
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            System.out.println("__bindService's disconnected success!!");
        }
    }

    // 点击按钮解绑服务
    public void click4(View v){
        unbindService(conn);
    }

    @Override
    protected void onDestroy() {
        // 当Activity销毁的时候要解绑服务
        unbindService(conn);
        super.onDestroy();
    }

5-3.总结

  1. 第一次绑定会执行服务的onBind()和onCreat()
  2. 当服务的onBind()返回null的时候ServiceConnection的onServiceConnected()不执行
  3. 第二次点击绑定服务按钮,服务没有反应
  4. ==同生同死(调用者和被调用者之间,即Activity和Service之间)==
  5. 服务不可以多次解绑,多次解绑会报异常
  6. 服务不能在设置页面找到,相当是隐形的服务
    7.== 服务一旦开启,就会在后台一直运行,知道用户杀死==

六、为什么要引入bingService

目的是为了调用服务里面的方法

七、通过bingService方式调用服务方法里面的过程

  1. 在服务的内容定义一个方法,让Activity去调用
    public void banZheng(int money){
        if(money > 1000){
            System.out.println("__开始办证");
        }else{
            System.out.println("这点钱还想办事?");
        }
    }
  1. 在服务的内容定义一个中间人对象IBinder(继承她的子类Binder)
    public class MyBinder extends Binder{
        public void callBanzheng(int m){
            // 调用办证的方法
            banZheng(m);
        }
    }
  1. 把定义的中间人对象在onBind()里返回
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return new MyBinder();
    }
  1. 在MainActivity的onCreat()里调用bindService的目的是为了获取我们定义的中间人对象
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this,WhyBindservice.class);
        conn = new MyCoon();
        bindService(intent, conn, BIND_AUTO_CREATE);
    }
  1. 获取中间人对象
    private class MyCoon implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            binder = (MyBinder)service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub

        }
    }
  1. 拿到了中间人对象就可以间接的调用服务里面的方法
    public void click1(View v){
        binder.callBanzheng(2000);
    }
  1. 销毁Activity的时候记得销毁服务,避免漏气

八、通过接口方式调用服务里面的方法

好处:可以隐藏代码内部的细节,让程序员只需暴露自己只想暴露的方法

8-1.方法

  1. 定义一个接口,把想暴露的方法放在放在该接口内
  2. 定义的中间人对象实现我们定义的接口
  3. 在获取对象的时候
binder = (Iservice)service;

九、百度音乐盒框架

[主要代码]

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

        /* 混合方式开启服务 */

        // 先调用startService()启动服务
        Intent intent = new Intent(this, MusicService.class);
        startService(intent);
        coon = new MyCoon();
        // 调用bindService,目的拿到IBinder对象
        bindService(intent,coon,BIND_AUTO_CREATE);

    }

十、aidl介绍

10-1.本地服务

运行在自己应用里面的服务

10-2.远程服务

运行在其他应用里面的服务

10-3.aidl(Android Interface definition language)

专门是用来进程间的通信

10-4.使用aidl步骤

  1. 把Iservice.java文件的后缀改为.aidl
  2. aidl这个语言不认识public,删除public
  3. 自动生成一个Iservice.java文件,系统自动帮我们生成了一个类Stub
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\Projects\\stu_Android\\day08_remoteService\\src\\com\\elnui\\day08_remoteservice\\Iservice.aidl
 */
package com.elnui.day08_remoteservice;
public interface Iservice extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.elnui.day08_remoteservice.Iservice
{
private static final java.lang.String DESCRIPTOR = "com.elnui.day08_remoteservice.Iservice";
/** Construct the stub at attach it to the interface. */
//..................................................
  1. 我们自己定义的IBinder对象直接继承Stub
  2. 保证2应用的aidl文件时同一个,保证aidl文件所在的包名相同
  3. 通过
iservice = Stub.asInterface(service);

拿到IBinder对象
7. 两个应用的清单配置
[local] 不用配置
[remote]

    <service android:name="com.elnui.day08_remoteservice.RemoteService">
        <intent-filter >
            <action android:name="com.elnui.callRemoteService"/>
        </intent-filter>
    </service>

其中[remote]清单文件里面的 ,
是由[local]绑定IBinder是指定的,如下

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

        // bindService 
        Intent intent = new Intent();
        intent.setAction("com.elnui.callRemoteService");
        conn = new MyConn();

        // 连接,为了回去IBinder对象
        bindService(intent, conn, BIND_AUTO_CREATE);
    }

十一、aidl的应用场景

补充

补充1:混合方式开启服务

需求:既想服务在后台长期运行,又想调用服务里面的方法
  1. 先调用startService()开启服务,能够保证服务在后台长期运行
  2. 再调用bindService()去获取中间人对象
  3. 然后调用unbindService()解绑服务
  4. 最后调用stopService()停止服务
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值