2016-05-08Android之广播+服务上
2016-05-08 06:04
603 查看
##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权限
相关文章推荐
- Android JNI/NDK开发之基本姿势<一>
- Android Studio Native调试
- Android Studio正确引入jar包
- Android Studio基本要素
- 一个Demo带你认识Design库,纯原生控件也能做出很漂亮的效果
- android studio 安装
- 如何优雅地使用NDK[功能补充]
- 谷歌推出Android 响应式布局控件 FlexboxLayout -弹性盒子模型
- Android 如何在屏幕切换的时候页面信息不被重置
- Android通用流行框架大全
- Android利用谷歌Gson解析Json生成bean类详解
- Activity全屏
- Android进阶学习-使用Canvas自定义ArcView(4)
- Android进阶学习-使用Canvas自定义音乐条形(5)
- Android 建立文件夹、生成文件并写入文本文件内容
- 如何查看android虚拟机的目录及文件
- Android自定义Toast的时长、位置、及显示的View
- Android Studio 单元测试入门
- Android底层开发之Audio HAL Android Audio Overview
- Android N 完全不同以往的四个新特性