2016-05-08Android之广播+服务上

##1. 广播接收者概念
BroadCastReceiver,是Android四大组件之一。必须注册。
1. 注册方式:1)静态注册2)动态注册

##2. IP拨号器 有序广播

activity_main.xml
    <EditText
        android:id="@+id/et_ipnum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="请输入IP号码" />
    <Button 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn"
        android:text="保存并退出"
        android:layout_gravity="center"
        android:textColor="#f00"
        android:onClick="btn_onclick"/>

MainActivity

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_ipnum = (EditText) findViewById(R.id.et_ipnum);
        /*将et_ipnum的数据存在sp上
         * 获得sp对象getSharedPreferences("IPnum", MODE_PRIVATE);
         * IPnum   系统自己加上.xml 后缀  MODE_PRIVATE 文件 权限为私有
         */
        sp = getSharedPreferences("IPnum", MODE_PRIVATE);
        /*
         * 数据的回显
         * sp.getString
         */
        String ipnum = sp.getString("ipnum", "");
        et_ipnum.setText(ipnum);

    }
public void btn_onclick(View view) {
        String ip_num = et_ipnum.getText().toString().trim();
        /*
         * 将数据保存在sp中
         * sp.edit()先编辑一下
         * putString存数据
         * .commit()最后提交
         */
        sp.edit().putString("ipnum", ip_num).commit();
        Toast.makeText(this, "ip号码保存成功"+ip_num, Toast.LENGTH_LONG).show();
        /*
         * 退出当前activity
         */
        finish();
    }

注册清单
<receiver 
            android:name="com.guyulei.broadcast1.IpNumBroadCast">
            <intent-filter >
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
            </intent-filter>
        </receiver>
加权限:
android.permission.PROCESS_OUTGOING_CALLS

IpNumBroadCast extends BroadcastReceiver

public class IpNumBroadCast extends BroadcastReceiver {
    private static final String TAG = "guyulei";
    private SharedPreferences sp;

    /*
     * 接收到广播时 系统回调
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        /*注册清单
         *<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
         */
        /*加权限android.permission.PROCESS_OUTGOING_CALLS
         * 获取用户拨打的号码并没有封装在intent内
         * 在函数内getResultData();
         */
        String resultData = getResultData();
        //获取保存在sp内的ipnum
        sp = context.getSharedPreferences("IPnum",Context.MODE_PRIVATE);
        String ip_num = sp.getString("ipnum", "");
        //修改电话号码为ip+resultData
        String newnum = ip_num+resultData;
        //将号码打出去对应getResultData()为setResultData
        setResultData(newnum);

        Log.d(TAG, "电话号码被修改成了"+newnum);
    }
}




##3. 案例-短信黑名单(***)

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

        et_blacknum = (EditText) findViewById(R.id.et_blacknum);
        //将黑名单号码保存在sp
        sp = getSharedPreferences("BlackNum", MODE_PRIVATE);
        //回显
        String blacknum = sp.getString("blacknum", "");
        et_blacknum.setText(blacknum);

    }
    public void saveandexit(View view) {
        String blacknum = et_blacknum.getText().toString().trim();
        //又忘了提交 妈的 commit()
        sp.edit().putString("blacknum", blacknum).commit();
        Toast.makeText(this, "黑名单保存成功", Toast.LENGTH_LONG).show();
        finish();
    }
清单文件:  优先级  短信广播
 <receiver 
            android:name="com.guyulei.broadcast.BlackNumBroadCast">
            <intent-filter 
                android:priority="1000">
                <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
            </intent-filter>
        </receiver>

添加的权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>

BlackNumBroadCast extends BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
        //权限:android.permission.RECEIVE_SMS
        /*
         * 获取短信的内容
         * pdus一种短信协议 里面封装数据
         */
        Bundle bundle = intent.getExtras();
        //数组中 的每个元素代表一条短信
        Object[] pdus = (Object[]) bundle.get("pdus");
        for (int i = 0; i < pdus.length; i++) {
             byte[] pdu = (byte[]) pdus[i];
             //将pdu字节数据转换为短信对象
             SmsMessage smsMessage = SmsMessage.createFromPdu(pdu);
             String address = smsMessage.getOriginatingAddress();

             String body = smsMessage.getMessageBody();
             //log
             Log.d(TAG, "接收到来自"+address+"的短信的内容为:"+body);

            //获取用户设置的黑名单
                sp = context.getSharedPreferences("BlackNum", Context.MODE_PRIVATE);
                String blacknum = sp.getString("blacknum", "");
            //若是黑名单 则拉黑 否则显示
                if(blacknum.equals(address)){
                    //拦截
                    Log.d(TAG, "这条短信被我拦截了!"+address+"..."+body);
                    //终止有序的广播
                    abortBroadcast();
                }else{
                    //不拦截
                }
        }
    }

###3.1 广播的分类
1. 无序广播(Normal BroadCast)
    1. 特点:不能被拦截,理论上所有的广播接收者可以同时接收到。
2. 有序广播(Ordered Broadcast)
    1. 特点:可以被拦截,哪个广播接收者的优先级高,哪个就优先接收


###3.2 广播接收者的优先级
1. 优先级的配置

         <receiver android:name="com.example.blacknum.BalckNumReceiver">
            <intent-filter android:priority="2000">
                <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
            </intent-filter>
        </receiver> 

2. 优先级的范围
    系统默认应用广播接收者的优先级是0,Google推荐的优先级范围是[-1000,+1000]


###3.2 终止有序广播
1. abortBroadcast();


##4. 案例-监听手机网络状态(***)
###4.1 获取到Android手机的网络状态
1. 添加获取网络状态权限

        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
2. 新的API

        private void getNetState() {
        //获取网络管理器的实例
        ConnectivityManager connectivityManager = (ConnectivityManager)this.getSystemService(CONNECTIVITY_SERVICE);
        //通过connectivityManager获取当前网络状态
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        //如果当前手机没有任何可用的网络,返回null
        if (activeNetworkInfo==null) {
            tv_state.setText("当期没有可用网络");
            Toast.makeText(this, "当前没有可用网络", Toast.LENGTH_SHORT).show();
            return;
        }else {
            //获取网络名称 WIFI MOBILE(LTE UTMS)
            String typeName = activeNetworkInfo.getTypeName();
            //如果是MOBILE,进一步区分是4G还是3G或者2G
            String subtypeName = activeNetworkInfo.getSubtypeName();
            tv_state.setText("当前网络:"+typeName+"/"+subtypeName);
            Toast.makeText(this, typeName+"/"+subtypeName, Toast.LENGTH_LONG).show();
        }
    }
3. 忘记反注册时的异常


        05-06 11:31:37.607: E/ActivityThread(26186): Activity com.example.listennetstate.MainActivity has leaked IntentReceiver com.example.listennetstate.MainActivity$NetStateReceiver@16c80d17 that was originally registered here. Are you missing a call to unregisterReceiver()?
4. 当Activity退出的时候,反注册广播接收者


        if (netStateReceiver!=null) {
            //反注册广播接收者
            unregisterReceiver(netStateReceiver);
            netStateReceiver = null;
        }


###4.2 复习老API
1.获取布局填充器(打气筒)

     LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);


###4.3 广播接收者的生效周期
1. 静态注册的
    1. 特点:一旦注册成功了,永久生效,只要不把APP卸载。在静态文件中注册的广播,如果该应用一旦启动过一次,那么就会被注册到系统中。
2. 动态注册的
    1. 特点:如果是在Activity中注册的,那么Activity销毁的时候,广播接收者也失效了

##5. 案例-监听开机启动(***)只能在清单文件中注册
开启启动的时候,系统会发出一个无序的广播,我们只需要监听该广播事件就可以实现开机启动。

1. 开机启动的Action
2. 开机启动需要添加的权限

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


###5.1 在广播中启动Activity的bug


        05-06 03:47:54.440: E/AndroidRuntime(1432): Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
1. 解决方案
    1. 在广播中启动Activity的时候,需要指定要创建一个任务栈

            //添加flag,让系统为我们的Activity创建一个新的任务栈
            intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

##6. 案例-监听屏幕的关闭和打开
1. 特别频繁的操作,只能动态的注册,比如:屏幕的开关,电量的改变。


##7. 发送自定义广播
###7.1 发送无序广播

    //发送无序广播
    sendBroadcast(intent);

###7.2 发送有序广播
1. 优先级
    1. 优先级相同的情况下,谁先注册,谁先接受
    2. 优先级相同的情况下,动态注册优先于静态注册接收到消息

2. 有序广播可以被拦截,但是最终广播接收者不能被拦截

##8. Service的基本概念(*)
1. 定义:

        A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. 

2. Service是Android四大组件之一,使用前必须在AndroidManifest.xml中注册。

3. 服务有两种形态
    1. 启动Stated
    2. 绑定Bound

4. 服务的注册
<service android:name="com.example.startservice.MyService"/>

##9. Service的启动和停止
1. startService
2. stopService

##10. startService的生命周期

1. 生命周期方法
    1. onCreate
    2. onStateCommand
    3. onDestroy


##11. 案例-来电窃听器
清单文件
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<receiver 
            android:name="com.guyulei.eavesdrop.BootStartReceiver">
            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

        <service 
            android:name="com.guyulei.eavesdrop.EavesdropService"></service>
    </application>

BootStartReceiver extends BroadcastReceiver:

private static final String TAG = "guyulei";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "开机服务启动了");
        //启动service
        context.startService(new Intent(context,EavesdropService.class));
    }

EavesdropService extends Service:
private TelephonyManager telephonymanager;
    private MediaRecorder recorder;
    private boolean isStart;
    private boolean isRinging;

public void onCreate() {
        //获取系统电话管理器
        telephonymanager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        /*
         * 参数1:new PhoneStateListener() 监听器,有很多回调函数,使用哪个由第二个参数说了算
         * 参数2:要监听事件的int常量
         */
        telephonymanager.listen(new PhoneStateListener(){


            /*
             * 参数1:int state电话的当前状态
             * 参数2:打进来的电话号码
             * 电话状态改变时  回调该方法 并返回改变后的状态
             */
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                switch(state){
                //空闲状态
                case TelephonyManager.CALL_STATE_IDLE:
                    //释放资源
                    if(isStart){
                        recorder.release();
                        recorder.stop();
                        isStart = false;
                    }else if(isRinging){
                        recorder.reset();
                        recorder.release();
                        isRinging = false;
                    }
                    break;
                //响铃状态
                case TelephonyManager.CALL_STATE_RINGING:
                    //准备录音机
                    if(recorder == null){
                        recorder = new MediaRecorder();
                    }
                    //设置音频源 麦克风
                    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    //设置文件输出的格式
                    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                    //设置音频的编码
                    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

                    //设置输出保存的文件
                    recorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+incomingNumber+"-"+new Date().getTime()+".3gp");
                    isRinging = true;
                    break;
                //接通状态
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    //录音
                    try {
                        //prepare()即创建文件
                        recorder.prepare();
                        recorder.start();
                        isStart = true;
                    } catch (IllegalStateException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                }               
            }

        }, PhoneStateListener.LISTEN_CALL_STATE);
    }
1. 步骤
    1. 定义一个开机启动的广播,开机的的时候,启动Service
    2. 在Service的onStart方法中监听用户的电话状态(新)
    3. 当有新来电的时候,开始录音,当挂电话的时候结束录音(新)

2. 电话的三种状态
    1. 空闲状态
    2. 响铃状态
    3. 接听状态
3. 注意添加权限、
    1. 开机启动广播权限
    2. 添加写sdcard权限


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值