一、为什么需要广播接收者(broadcastReceiver)
1.有什么样的人员听广播 老人,出租车司机
2.听广播必须:电台,收音机,调频道
3.Android内部已经定义好了电台,已经定义好了一些广播事件,如外拨电话,短信到来等等
4.使用broadcastReceiver去接收系统定义好的这些事件
5.javame javase javaee
6.定义广播接收者目的是为了方便安卓开发者开发
二、案例
2-1.案例——ip拨号器
360永久免费 瑞星 卡巴斯基
1.在清单文件中配置receiver,并添加用户权限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<application
//......
<!-- 配置广播接收者 -->
<receiver android:name="com.elnui.day07_caseip.OutGoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
</application>
2.新建一个类继承BroadcastReceiver
public class OutGoingCallReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// 获取用户输入的ip号码在config.xml文件中
SharedPreferences sp = context.getSharedPreferences("config", 0);
String number = sp.getString("ipnumber", "");
// 获取当前拨打的电话
String num = getResultData();
// 在当前号码前假17951
// 判断当前号码是不是长途号码
if(num.startsWith("0")){
// 修改拨打的号码
setResultData(number + num);
}
}
}
3.getResultData()
Retrieve the current result data, as set by the previous receiver. Often this is null.
4.setResultData()
Change the current result data of this broadcast;
only works with broadcasts sent through Context.sendOrderedBroadcast.
This is an arbitrary string whose interpretation is up to the broadcaster.
5.总结
- BroadcastReceiver是一个抽象类,没有上下文
public abstract class BroadcastReceiver{}
- public void onReceive(Context context, Intent intent) {},该方法中的context就是上下文
2-2.案例——sd卡监听器
1.onReceive()方法
- intent.getAction(); //获取当前广播的事件类型
Retrieve the general action to be performed, such as ACTION_VIEW.
The action describes the general way the rest of the information in the intent should be interpreted
-- most importantly, what to do with the data returned by getData.
2.清单文件配置
<receiver android:name="com.elnui.day07_casesd.SdcardStateReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<!-- 小细节,这里必须配置data,约束类型叫file,因为sd里面的数据类型是file -->
<data android:scheme="file"/>
</intent-filter>
</receiver>
说明:<intent-filter>下必须添加<data android:scheme="file"/>
3.代码
public class SdcardStateReceiver extends BroadcastReceiver{
// 当SD卡状态发生改变时调用
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if("android.intent.action.MEDIA_MOUNTED".equals(action)){
System.out.println("SD卡挂载了。");
}else if("android.intent.action.MEDIA_UNMOUNTED".equals(action)){
System.out.println("SD卡挂载了。");
}
}
}
2-3.案例——短信监听器
1.代码
public class SmsListerReceiver extends BroadcastReceiver {
// 当短信到来的时候执行
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
System.out.println("Receive sms.............success!!!");
// 获取发送者的号码和内容
Object []objects = (Object[]) intent.getExtras().get("pdus");
for (Object obj : objects) {
// 获取SmsMessage的实例
SmsMessage smg = SmsMessage.createFromPdu((byte[])obj);
String messageBody = smg.getMessageBody();
String messageAddr = smg.getOriginatingAddress();
System.out.println("___Address:" + messageAddr + ":" + messageBody);
}
}
}
2.清单文件配置
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<receiver android:name="com.elnui.day07_casesms.SmsListerReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
3.类SmsManager
- pdu也是封装短信的一种格式
4.类SmsMessage (android.telephony包下)
通过这个API拿到短信的信息
通过静态的createFromPdu()即可获得实例
- getOriginatingAddress(); // 获取号码
- getMessageBody(); // 获取内容
2-4.卸载安装
1.代码
public class StatusReceiver extends BroadcastReceiver {
// 当有新的应用被安装或者卸载时调用
@Override
public void onReceive(Context context, Intent intent) {
// 获取当前广播的类型
String action = intent.getAction();
if("android.intent.action.PACKAGE_INSTALL".equals(action)){
System.out.println("___PACKAGE_INSTALL");
}else if("android.intent.action.PACKAGE_REMOVED".equals(action)){
System.out.println("___PACKAGE_REMOVED");
}else if("android.intent.action.PACKAGE_ADDED".equals(action)){
System.out.println("___PACKAGE_ADDED" + intent.getData());
}
}
}
2.清单文件配置(此处得配置data)
<receiver android:name="com.elnui.day07_caseinstall.StatusReceiver">
<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_ADDED"/>
<!-- 小细节:还需配置一个data -->
<data android:scheme="package"/>
</intent-filter>
</receiver>
android.intent.action.PACKAGE_INSTALL是谷歌工程师预留的字符段
3.getData()
intent.getData()可以拿到包名
2-5.开机启动
1.代码
public class BootReceiver extends BroadcastReceiver {
// 当手机重启时调用
@Override
public void onReceive(Context context, Intent intent) {
// 开启Activity
Intent x = new Intent(context,MainActivity.class);
// 添加标记
x.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(x);
}
}
2.清单文件配置
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application>
<receiver android:name="com.elnui.day07_reboot.BootReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
3.注意
不能在广播接收者里面开启Activity,需要添加一个任务栈的标记
开机启动一定要加RECEIVE_BOOT_COMPLETED权限
// 添加标记
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
4.补充
在页面按返回键会调用onBackPressed()
@Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
}
三、不同版本广播的特点
四、有序广播和无序广播
4-1.无序广播
比如新闻联播,到7点就播
1.广播发送者
代码
public void click1(View v){
Intent intent = new Intent();
intent.setAction("com.elnui.custom");
intent.putExtra("name", "准时开播");
sendBroadcast(intent);
}
2.广播接收者
代码
public class wuxuRecelver extends BroadcastReceiver {
// 当接收到自定义的广播时执行
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String str = intent.getStringExtra("name");
Toast.makeText(context, str, 1).show();
}
}
清单文件
<receiver android:name="com.elnui.day07_recelve.wuxuRecelver">
<intent-filter >
<action android:name="com.elnui.custom"/>
</intent-filter>
</receiver>
4-2.有序广播
类似中央发送红头文件,按照优先级进行接收
1.发送者
代码
// 点击发送有序广播
public void click1(View v){
Intent intent = new Intent();
intent.setAction("com.elnui.sendOrderBroadcast");
/**
* intent 意图
* receiverPermission 接收的权限
* resultReceiver 最终的recriver
* scheduler handler
* initialCode 初始码
* initialData 初始化数据
* initialExtras 额外数据
*
* */
sendOrderedBroadcast(intent, null, new FinalReceiver(), null, 1, "有序广播-1000", null);
}
2.接收者(以其中一个为例)
代码
public class CountryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String str = getResultData();
Toast.makeText(context, "乡_>>"+str, 1).show();
setResultData("有序广播-100");
// 终止广播
//abortBroadcast();
}
}
清单文件
<!-- 省长优先级 最高优先级-->
<receiver android:name="com.elnui.day07_receiver.ProvienceReceiver">
<intent-filter android:priority="1000">
<action android:name="com.elnui.sendOrderBroadcast"/>
</intent-filter>
</receiver>
<!-- 市长优先级 -->
<receiver android:name="com.elnui.day07_receiver.CityReceiver">
<intent-filter android:priority="100">
<action android:name="com.elnui.sendOrderBroadcast"/>
</intent-filter>
</receiver>
<!-- 乡长优先级 -->
<receiver android:name="com.elnui.day07_receiver.CountryReceiver">
<intent-filter android:priority="10">
<action android:name="com.elnui.sendOrderBroadcast"/>
</intent-filter>
</receiver>
<!-- 村民优先级 -->
<receiver android:name="com.elnui.day07_receiver.PeopleReceiver">
<intent-filter android:priority="1">
<action android:name="com.elnui.sendOrderBroadcast"/>
</intent-filter>
</receiver>
3.最终接收者
public class FinalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String str = getResultData();
Toast.makeText(context, "报告_>>"+str, 1).show();
}
}
说明:最终接收者无需再清单文件中配置
4.abortBroadcast()
终止广播
5.有序和无序广播的区别
- 无序广播不可以被终止,调用abortBroadcast()会在日志文件中打印警告
- 无序广播数据不可以修改
五、特殊广播接收者
操作特别频繁的广播事件,比如屏幕的锁屏和解锁,电池电量的变化。这种事件的广播在清单文件注册无效
5-1.注册广播接收者的两种方式
1. 使用代码动态注册 Context.registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 动态去注册广播接收者
ScreenReceiver sc = new ScreenReceiver();
/*
* <action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
* */
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
registerReceiver(sc, intentFilter);
}
}
04-16 10:24:40.719: E/ActivityThread(2270): android.app.IntentReceiverLeaked:
Activity com.elnui.day07_broadcast.MainActivity has leaked IntentReceiver com.elnui.day07_broadcast.ScreenReceiver@b0fc74e8
that was originally registered here. Are you missing a call to unregisterReceiver()?
注意,当Activity销毁的时候,要取消注册广播接收者unregisterReceiver()
2. 在清单文件通过receiver节点静态注册
六、样式和主题
6-1.样式
样式的作用一般在控件上,样式的作用范围比较窄
6-2.主题
主题一般作用在Activity或者Application节点下,作用范围相抵较大
6-3.二者定义的方式一样
七、国际化
i18n
在res目录下创建不同国家语言环境的目录即可,如values-ch,values-en..
八、常见对话框
8-1.Toast
8-2.普通对话框
public void click1(View v){
// 通过Builder构建器来构造
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("警告"); // 标题
builder.setMessage("世界上最遥远的距离是没有网络"); //内容
builder.setPositiveButton("确定", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
System.out.println("___点击了确定按钮");
}
}); //
builder.setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
System.out.println("___点击了取消按钮");
}
}); //
builder.show();
}
8-3.单选对话框
// 点击,弹出一个单选对话框
public void click2(View v){
// 通过Builder构建器来构造
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("请选择课程");
items = new String[] {"安卓","IOS","C","C++","C#"};
builder.setSingleChoiceItems(items, 0, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
System.out.println("___点击了单选按钮");
// 取出选择的内容
String str = items[which];
Toast.makeText(getApplicationContext(), str, 1).show();
// 关闭单选框
dialog.dismiss();
}
});
builder.show();
}
8-4.多选对话框
// 点击,弹出一个多选对话框
public void click3(View v){
// 通过Builder构建器来构造
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("请选择水果");
final String frults[] = new String[] {"苹果","西瓜","桔子","榴莲","哈密瓜"};
checkedItems = new boolean[] {true,false,false,false,false};
builder.setMultiChoiceItems(frults, checkedItems, new OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
// TODO Auto-generated method stub
}
});
builder.setPositiveButton("确定", new OnClickListener() {
StringBuffer sb = new StringBuffer();
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
// 把选中的条目数据取出来
for (int i = 0; i < checkedItems.length; i++) {
if(checkedItems[i]){
String frult = frults[i];
sb.append(frult + "-");
}
}
Toast.makeText(getApplicationContext(), sb.toString(), 1).show();
// 关闭单选框
dialog.dismiss();
}
});
builder.show();
}
8-5.进度条对话框
PrograssBar
与进度相关的控件,都可以在子线程更新UI
// 点击,弹出进度条对话框
public void click4(View v){
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setTitle("正在玩命加载。。。。");
// 设置进度条样式
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// 线程
new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
// 设置最大进度
dialog.setMax(100);
for (int i = 0; i < 100; i++) {
// 设置进度
dialog.setProgress(i);
// 延时
SystemClock.sleep(50);
if(dialog.getProgress() == 99){
dialog.dismiss();
}
}
super.run();
}
}.start();;
// 最后show()
dialog.show();
}
九、两种上下文的区别
9-1.getApplicationContext()
返回的对象是Context对象【父类】
9-2.this
最终继承Context对象【子类】
注意: 对话框只能用this
十、安卓中的动画
10-1.帧动画
- 加载一系列的图片资源
- The AnimationDrawable class is the basis for Drawable animations.
res/drawable/my_animation.xml - 在android2.3之前的手机上需要用兼容性写法,使用线程
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@drawable/girl_1" android:duration="200" />
<item android:drawable="@drawable/girl_2" android:duration="200" />
<item android:drawable="@drawable/girl_3" android:duration="200" />
<item android:drawable="@drawable/girl_4" android:duration="200" />
<item android:drawable="@drawable/girl_5" android:duration="200" />
<item android:drawable="@drawable/girl_6" android:duration="200" />
<item android:drawable="@drawable/girl_7" android:duration="200" />
<item android:drawable="@drawable/girl_8" android:duration="200" />
<item android:drawable="@drawable/girl_9" android:duration="200" />
<item android:drawable="@drawable/girl_10" android:duration="200" />
<item android:drawable="@drawable/girl_11" android:duration="200" />
</animation-list>
onCreat()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView rocketImage = (ImageView)findViewById(R.id.iv);
// 设置背景资源
rocketImage.setBackgroundResource(R.drawable.my_animation);
// 获取AnimationDraw类型
AnimationDrawable rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
// 开启动画
rocketAnimation.start();
}
10-2.View动画(补间动画)
10-3.属性动画
笔记:
笔记一:Android TextView 文字居中
两种方法
- 在xml文件设置:Android:gravity=”center”
- 在程序中设置:m_TxtTitle.setGravity(Gravity.CENTER);