Android中的广播与服务(包含代码)
1.为什么需要广播接受者
广播接受者:收音机;
电台:中央人民广播电台 93.4MHZ 发送消息;
收音机:买一个收音机,收音机接受广播;
原因:Android系统内部内置了一些公共事件的广播消息(电量不足、电量充满、接收到短信、外拨电话、SD卡状态等)。
当开发人员接收到这些消息事件后可以开发一些对用户有用的业务逻辑;
2.广播接受者案例_ip拨号器(重点)
1、买个收音机:
public class IPDialBroadcastReceiver extends BroadcastReceiver {
/**
* 当广播接收者接收到广播消息时会调用这个方法
*/
@Override
public void onReceive(Context context, Intent intent) {
//这里面就是我们想做的事
}
}
2.插上电池:
在配置文件中配置receiver:
<receiver android:name="com.qaa.ipdialIPDialBroadcastReceiver">
</receiver>
3.调整到一定的频道:receiver 里有intent-filter, intent-filter里有action。
<receiver android:name="com.qaa.ipdial.IPDialBroadcastReceiver">
<intent-filter >
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
3.广播接受者案例_短信特殊案例(重点)
pdus : protocol data unit 协议数据单元;
广播接收者的特点:(注意)
1.即使广播接收者没有运行,当广播消息达到的时候,在Android4.0之前系统会自动的启动广播接收者,然后调用onReceive方法处理消息;
2.Android4.0之后,google处于安全上的设计,要求包含广播接收者的应用程序必须有界面,并且至少运行过一次,广播接收者才会生效;
3.Android4.0版本的强行停止相当于冻结一个应用,一旦应用程序被用户强行停止了,广播接受者就不会生效了。直到用户手工打开这个应用程序为止;
代码:
package com.qaa.SMSListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsMessage;
public class SMSBroadcastReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent data)
{
Object[] objs = (Object[]) data.getExtras().get("pdus");
for(Object obj : objs){
//创建一个短信体
SmsMessage sms = SmsMessage.createFromPdu((byte[])obj);
//获得一个短信的内容
String content = sms.getMessageBody();
//获得一个短信的源地址
String phone = sms.getOriginatingAddress();
System.out.println("content==="+content+"; phone==="+phone);
}
}
}
清单文件:
//一定要加权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<receiver android:name="com.qaa.SMSListener.SMSBroadcastReceiver">
<intent-filter >
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
4.广播接受者案例_sd卡状态(重点)
测试时使用2.3的模拟器或者真机测试,因为Android4.0之后的模拟器去掉了SD卸载、挂载、移除的功能。
配置文件:
<receiver android:name="com.qaa.sdlistener.SDBroadcastReceiver">
<intent-filter >
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<action android:name="android.intent.action.MEDIA_REMOVED"/>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<!--注意: 必须加上这个属性 -->
<data android:scheme="file" />
</intent-filter>
</receiver>
代码:
package com.qaa.sdlistener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class SDBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获得广播的事件类型
String action = intent.getAction();
if("android.intent.action.MEDIA_UNMOUNTED".equals(action)){
Toast.makeText(context, "SD卡被拔掉............", 0).show();
}else if("android.intent.action.MEDIA_REMOVED".equals(action)){
Toast.makeText(context, "SD卡被移除............", 0).show();
}else if("android.intent.action.MEDIA_MOUNTED".equals(action)){
Toast.makeText(context, "SD卡已插上............", 0).show();
}
}
}
5.广播接受者案例_开机启动(重点)
步骤:
1.买个收音机(继承BroadcastReceiver)
2.插上电池(配置好文件)
3.调整到一个频道 (用广播接受着做具体的事)
要做的事情:
1.让软件开启后关闭不了:
2.禁用返回键和最小化键(小房子键);
配置文件:
//注意要添加这个广播接受者的权限,android.permission.RECEIVE_BOOT_COMPLETED
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name="com.qaa.bootcomplete.BootCompleteBroadcastReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
代码:
BootCompleteBroadcastReceiver.java:
package com.qaa.bootcomplete;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootCompleteBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context,MainActivity.class);
//告诉activity使用自己的任务栈来维护界面
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//使用context开启Activity。
context.startActivity(i);
}
}
MainActivity.java:
package com.qaa.bootcomplete;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void pay(View view){
Toast.makeText(this, "非常感谢,期待下次为您服务...", 0).show();
//关闭当前界面
finish();
}
/**
* 禁用返回键 */
@Override
public void onBackPressed()
{
}
}
6.广播接受者案例_卸载安装(重点)
配置文件:
<receiver android:name="com.qaa.SoftwareBroadcastReceiver">
<intent-filter >
<action android:name="android.intent.action.PACKAGE_INSTALL"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_REPLACED"/>
<!-- 必须添加这个属性 -->
<data android:scheme="package" />
</intent-filter>
</receiver>
代码:
package com.qaa.azxz;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class SoftwareBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if("android.intent.action.PACKAGE_INSTALL".equals(action)){
Toast.makeText(context, "有一个新软件被安装了........", 0).show();
}else if("android.intent.action.PACKAGE_REMOVED".equals(action)){
Toast.makeText(context, "有一个软件被卸载了........", 0).show();
}else if("android.intent.action.PACKAGE_REPLACED".equals(action)){
Toast.makeText(context, "有一个软件升级了........", 0).show(); } }
}
7.发送自定义广播
代码:
Intent intent = new Intent();
//指定事件类型
intent.setAction("com.qaa.HMSSQ");
//设置发送的数据
intent.putExtra("news", "Android之声频道,每天准时开播....");
//发送广播消息
sendBroadcast(intent);
8.有序广播和无序广播(重点)
有序广播:发送的广播消息会按照广播接收者的优先级从高到低,一级一级的发送消息。消息可以被拦截,可以被修改。
无序广播:只要是广播接收者指定了接收的事件类型,就可以接收到发送出来的广播消息。不能修改消息。
自定义一个有序的广播:
Intent intent = new Intent();
intent.putExtra("news", "Android之声频道,每天准时开播...."); //
//发送有序的广播消息
sendBroadcast(intent);
//intent 意图对象
//receiverPermission 指定广播接收者的权限,只有设置了这个权限的广播接收者才能接收到消息
//resultReceiver 指定哪个广播接收者最后接收到消息
//scheduler 消息处理器
//initialCode 初始化的消息码
//设置事件类型
intent.setAction("com.qaa.FFNTBT");
//发送有序的广播消息
sendOrderedBroadcast(intent, null, null, null, 1, "补贴9000块钱", null);
自定义的广播接收者:
<receiver android:name="com.qaa.broadcastreceiver.ProvinceBroadcastReceiver">
<intent-filter android:priority="1000"(实际上这并不是一个最大的优先级)>
<action android:name="com.qaa.FFNTBT"/>
</intent-filter>
</receiver>
public class ProvinceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获得广播发送的数据
String data = getResultData();
System.out.println("===========我是省级人民政府,接收到 补贴:"+data+"==============");
//修改消息 (可修改)
setResultData("贴500块钱"); }
}
9.服务和进程优先级
1、什么服务?
windows下:没有界面,长期运行在后台的应用程序;
Android下:没有界面,长期运行在后台的应用程序(没有界面activity);
2、什么进程?
进程:运行应用程序的载体。 当应用程序已启动的时候,系统就会创建出来一个相应的进程,这个进程负责运行dalvik虚拟机,我们开发的应用程序是运行dalvik虚拟机里面的。
应用程序:Android的四大组件放在一起就是应用程序。
当应用程序已启动的时候,系统就会创建出来一个相应的进程,当应用程序退出的时候,进程并没有退出;当应用程序再次打开的时候,会使用已经存在的进程。
进程太多,导致内存空间不够使用。
解决办法:系统给每个进程分配一个优先级,当内存空间不够用的时候,会根据进程的优先级,从低到高,逐级杀死进程,腾出内存空间。
进程的生命周期:
1.当应用程序已启动的时候,进程被创建;
2.当手工结束进程,或者强制停止应用程序可以结束进程、系统内存空间不够使用,系统会自动杀死低优先级的进程;
进程的等级:
1. Foreground process(前台进程)
应用程序界面可见,用户正在操作,activity的onresume方法被执行了,可以相应点击事件。
2. Visible process (可视进程)
应用程序的ui界面,用户还可以看到,但是不能操作了。
3. Service process (服务进程)
应用程序没有界面,但是有一个后台的服务还处于运行状态
4. Background process(后台进程)
应用程序没有服务处于运行状态,应用程序被最小化了,activity执行了onstop方法
5. Empty process (空进程)
没有任何组件运行,所有的activity都关闭了,任务栈清空了。
10.服务的特点
服务的生命周期:
1.服务被开启(调用startService方法):创建一个服务对象,onCreate、onStartCommand;
2.停止服务(调用stopService方法):onDestroy,销毁服务对象;
服务的特点:
1.服务只能被创建一次,可以被开启多次,多次开启时值调用onStartCommand;
2.服务只能被停止一次,多次停止不会执行任何操作;
应用场景:需要长期运行在后台,而且需要与服务器端定时交互数据。
11.电话特殊的模板代码(重点)
要做的事情:
1.让应用程序长期运行在后台,电话的状态;
2.把通话内容录音;
代码:
MainActivity.java:
package com.qaa.outcalllistener;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建开启服务意图对象
Intent intent = new Intent(this,OutCallService.class);
//开启服务
startService(intent);
}
}
OutCallService.java:
package com.qaa.outcalllistener;
import android.app.Service;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class OutCallService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null; }
@Override
public void onCreate() {
super.onCreate();
// 得到电话的服务对象
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
//电话的状态
tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE); }
private class MyListener extends PhoneStateListener {
private MediaRecorder r;
/**
* 电话状态发生变化时调用这个方法 state 电话状态:闲置、铃声响起、接通电话 incomingNumber 呼入的电话号码
*/ @Override public void onCallStateChanged(int state, String incomingNumber)
{ super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:// 闲置状态
System.out.println("=======CALL_STATE_IDLE======");
if (r != null) {
// 停止录音
r.stop();
r.release();
r = null;
//访问网络上传文件 }
break;
case TelephonyManager.CALL_STATE_RINGING:
// 铃声响起状态
System.out.println("=======CALL_STATE_RINGING======");
try { r = new MediaRecorder();
// 设置音频来源
r.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置音频的格式
r.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// 设置音频文件保存的路径
r.setOutputFile(Environment.getExternalStorageDirectory() + "/456.3gp");
// 设置音频文件的编码
r.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
r.prepare();
} catch (Exception e) {
e.printStackTrace();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// 接通电话状态
System.out.println("=======CALL_STATE_OFFHOOK======");
// 开始录音
r.start();
break;
} }
} }
配置文件:
<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 android:name="com.itheima.outcalllistener.OutCallService"></service>