您的位置:首页 > Web前端 > CSS

安卓基础第七天(四大组件之BroadcastReceiver,样式主题,国际化,对话框)

2018-02-21 19:14 465 查看

BroadcastReceiver简介

Broadcast 是一种广泛运用的在应用程序之间传输信息的机制

BroadcastReceiver 是对发送出来的Broadcast 进行过滤接受并响应的一类组件

简单创建BroadcastReceiver

接收SD卡移除时发送的广播

1.新建一个SDCardUnmountedReceiver 类继承BroadcastReceiver 类当接收到匹配广播之后就会执行onReceive 方法

public class SDCardUnmountedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "SDCard 已经被移除!", 0).show();
}
}


2.注册SDCardUnmountedReceiver

注册一个广播接收者有两种方式

静态注册:在AndroidManifest.xml 中注册广播

清单文件中声明,需要在其中配置指定接收广播的动作(action),在AndroidManifest.xml 文件中添加如下配置:

<receiver android:name="com.itheima.broadcastReciver.SDCardUnmountedReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<data android:scheme="file" >
</data>
</intent-filter>
</receiver>


动态注册:在Java 代码中注册

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter(
"android.intent.action.MEDIA_UNMOUNTED");
intentFilter.addDataScheme("file");
registerReceiver(new SDCardUnmountedReceiver(), intentFilter);
System.out.println("广播接收器已经注册成功。");
}
}


两种注册的区别

代码注册:它不是常驻型广播,也就是说广播跟随程序的生命周期,一旦代码所在进程被杀死,广播接收者就失效

清单文件注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。一旦应用程序被部署到手机,广播接收者就会生效,高版本需要启动过一次才能接收到广播

PS:3.2 版本以上出于安全问题:从未启动过的广播接收程序,默认是接收不到广播的,必须有一个界面,然后通过界面启动一次这个程序。

生命周期

广播接收者也是运行在主线程中,所以在广播接收者的onReceive 方法内不能有耗时的操作,需要放在子线程中做

但是onReceive 的生命周期很短,有可能广播接收者结束,子线程还没有结束,这时广播接收者所在进程很有可能被杀掉,这样子线程就会出问题

所以耗时操作最好放到service 服务中。

广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁

Android中常见广播

短信监听

需要的权限

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


清单配置 PS:android 4.2 后废除了此action

<receiver android:name="com.itheima.smslistener.SmsListenerReceiver">

<intent-filter >

<action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter>

</receiver>


代码

public class SmsListenerReceiver extends BroadcastReceiver {
//当短信到来的时候执行
@Override
public void onReceive(Context context, Intent intent) {
//获取发送者的号码 和发送内容
Object []objects = (Object[]) intent.getExtras().get("pdus");
for (Object obj : objects) {
//[1]获取smsmessage实例
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);
//[2]获取发送短信的内容
String messageBody = smsMessage.getMessageBody();
String address = smsMessage.getOriginatingAddress();
System.out.println("body:"+messageBody+"-----"+address);
}
}
}


监听系统开机

拦截的广播

<action android:name="android.intent.action.BOOT_COMPLETED"></action>


需要的权限

PS:3.2 以上版本必须加权限,,3.2 以上的版本如果用户没有启动过程序, 接收不到开启启动完成的广播

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


代码

java.lang.RuntimeException: Unable to start receiver com.itheima.bootreceiver.BootReceiver: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?


public class BootReceiver extends BroadcastReceiver {

//当手机重新启动的时候调用
@Override
public void onReceive(Context context, Intent intent) {
//在这个方法里面开启activity
Intent intent2 = new Intent(context,MainActivity.class);
//☆☆☆注意 不能在广播接收者里面直接开启activity  需要添加一个标记 添加一个任务栈的标记
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//开启activity
context.startActivity(intent2);
}
}


监听卸载安装

拦截的广播

<action android:name="android.intent.action.PACKAGE_ADDED"></action>


<action android:name="android.intent.action.PACKAGE_REMOVED"></action>


需要指定scheme: package

<data android:scheme="package"/>


代码

public class AppStateReceiver extends BroadcastReceiver {

//当有新的应用被安装  了  或者有应用被卸载 了  这个方法调用
@Override
public void onReceive(Context context, Intent intent) {

//获取当前广播事件类型
String action = intent.getAction();

//PACKAGE_INSTALL为预留无效action
if ("android.intent.action.PACKAGE_INSTALL".equals(action)) {
System.out.println("应用安装了11111");
}else if ("android.intent.action.PACKAGE_ADDED".equals(action)) {
System.out.println("应用安装了22222");
}else if("android.intent.action.PACKAGE_REMOVED".equals(action)){
System.out.println("应用卸载了"+intent.getData());
}

}

}


监听打电话

拦截的广播:

<action android:name="android.intent.action.NEW_OUTGOING_CALL"></action>


需要的权限:

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


特殊广播的接收者

比如操作特别频繁的广播事件 ,屏幕的锁屏和解锁, 电池电量的变化

这样的广播接收者在清单文件里面注册无效

报错

Activity com.itheima.screen.MainActivity has leaked IntentReceiver com.itheima.screen.ScreenReceiver@b6486088 that was originally registered here. Are you missing a call to

unregisterReceiver()?


发送自定义广播

无序广播

符号某广播条件的所有广播接收者的特点,无序,无优先级,不可中断,接收者不可传递数据

BroadcastReceiver trying to return result during a non-ordered broadcast


无序广播使用sendBroadcast 方法来发送

广播时可设置接收者权限,仅当接收者含有权限才能接收

接收者的也可设置发送方权限,只接收含有权限应用的广播

Receiver 节点增加属性permission

发送广播时,通过intent.setFlags(intent.flag_include_stopped_pakeages),包含从

未启动过的程序,这样设置,可以让从未启动的接收者也收到广播

//点击按钮 发送一条无序广播
public void click(View v) {
Intent intent = new  Intent();
intent.setAction("com.itheima.custom");
intent.putExtra("name", "新闻联播每天晚上 7点准时开整!!");
sendBroadcast(intent);//发送无序广播
}


有序广播

有序广播使用sendOrderedBroadcast 方法来发送

接收者可以在中定义android:priority 定义优先级,数字越大优先级越高,官方定义范围是:

1000(最高) ~ -1000(最低),系统默认优先级是0

有序广播可以被拦截或添加数据,优先级高的接收者可以拦截优先级低的

使用abortBroadcast 方法拦截,setResultExtras(Bundle)传递数据

代码

发送有序广播

sendOrderedBroadcast(intent, null, new FinalReceiver(), null, 1, "习大大给每个村民发了1000斤大米", null);


接收者

public class ProvienceReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
//[1]获取发送广播携带的数据
String content= getResultData();
//[2]显示结果
Toast.makeText(context, "省:"+content, 1).show();
//[2.1]终止广播
abortBroadcast();

//[3]修改数据
setResultData("习大大给每个村民发了500斤大");
}
}


最终接收者,被拦截的广播依然可以接收到,无需注册

public class FinalReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

//[1]获取发送广播携带的数据
String content= getResultData();

//[2]显示结果
Toast.makeText(context, "报告习大大:"+content, 1).show();
}
}


样式主题

样式

Android Style 类似网页设计中的级联样式CSS 设计思路,可以让设计与内容分离,并且可以方便的继承、覆盖、重用

同CSS 一样,样式的引入遵循就近原则,在控件上定义的属性会覆盖被引入的样式中的同一个属性

在工程中res->values->styles.xml 文件定义样式

<style name="btn_style">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:textSize">20sp</item>
<item name="android:textColor">#ff0000</item>
<item name="android:text">自定义样式</item>
</style>
<!-- 继承上一个样式,相同的属性则覆盖父类 -->
<style name="btn_style_child" parent="btn_style">
<item name="android:textColor">#0000ff</item>
</style>


使用个style=”@style/btn_style”属性添加样式

主题

主题的定义与样式的定义相同,都是定义在styles.xml 文件下

不同之处在于主题是作用在Activity 上的

主题通过定义AndroidManifest.xml 文件中的和节点下的”android:theme”属性作用在整个应用或者某个Activity

当主题和样式属性发生冲突时,样式的优先级高于主题

透明主题:@android:style/Theme.Translucent

reference–>android–>R.style 中查看文档

国际化

Internationalization太长也简称为I18N

Android 可以通过资源文件非常方便的实现程序的国际化。

res/目录下

1.创建名称为values-zh-rCN、values-zh-rTW 和values-en-rUS的文件夹

2.然后在每个文件夹中创建一个对应的strings.xml 文件,并在该文件中定义对应语言的字符串即可

3.图片也可以进行国际化,创建名称类似drawable-zh-rCN,drawable-zh-rTW 这样的文件夹,将图片资源存放在文件夹下即可

帧动画

Drawable Animation(Frame Animation):帧动画,就像GIF 图片,通过一系列Drawable 依次显示来模拟动画的效果。

Android 中的常见对话框

Android 中常用的对话框有:

通知对话框、列表对话框、单选对话框、多选对话框以及进度对话框。

通知对话框、列表对话框、单选以及多选对话框由AlertDialog.Builder创建

进度对话框由ProgressDialog 创建。

代码

public class MainActivity extends Activity {

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

//点击按钮 弹出一个普通对话框
public void click1(View v){

//通过builder 构建器来构造
AlertDialog.Builder  builder = new Builder(this);
builder.setTitle("警告");
builder.setMessage("世界上最遥远的距离是没有网络 ");
builder.setPositiveButton("确定", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
System.out.println("点击了确定按钮");
}
});
builder.setNegativeButton("取消", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
System.out.println("点击了取消按钮 ");
}
});

//最后一步 一定要记得  和Toast 一样  show出来
builder.show();

}

//点击按钮 弹出一个单选对话框
public void click2(View v){

//通过builder 构建器来构造
AlertDialog.Builder  builder = new Builder(this);
builder.setTitle("请选择您喜欢的课程");

final String items[] = {"Android","ios","c","C++","html","C#"};

//-1代表没有条目被选中
builder.setSingleChoiceItems(items, -1, new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {

//[1]把选择的条目给取出来
String item = items[which];

Toast.makeText(getApplicationContext(), item, 1).show();

//[2]把对话框关闭
dialog.dismiss();
}
});

//最后一步 一定要记得  和Toast 一样  show出来
builder.show();

}

//点击按钮 弹出一个对选对话框
public void click3(View v){

//通过builder 构建器来构造
AlertDialog.Builder  builder = new Builder(this);
builder.setTitle("请选择您喜欢吃的水果");

final String items[] = {"香蕉","黄瓜","哈密瓜","西瓜","梨","柚子","榴莲"};
final boolean[] checkedItems={true,false,false,false,false,false,true};
builder.setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() {

@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {

}
});

builder.setPositiveButton("确定", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {

//把选中的 条目的数据给我取出来

StringBuffer sb = new StringBuffer();
for (int i = 0; i < checkedItems.length; i++) {

//判断一下 选中的
if (checkedItems[i]) {

String fruit = items[i];
sb.append(fruit + "  ");
}

}
Toast.makeText(getApplicationContext(), sb.toString(), 1).show();
//关闭对话框
dialog.dismiss();

}
});

//最后一步 一定要记得  和Toast 一样  show出来
builder.show();
}

//点击按钮 弹出一个进度条对话框
public void click4(View v){
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setTitle("正在玩命加载ing");
//设置一下进度条的样式
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
//最后一步一定要记得show 出来
dialog.show();
//创建一个子线程
new Thread(){public void run() {

//设置进度条最大值
dialog.setMax(100);

//设置当前进度
for (int i = 0; i <=100 ; i++) {

dialog.setProgress(i);
//睡眠一会
SystemClock.sleep(50);

}
//关闭对话框
dialog.dismiss();

};}.start();
}
}


activity.this与getApplicationContext()区别

一般情况:可以用activity.this.代替getApplicationContext()

activity,弹出对话框时,生命周期方法:onpause()、onResume()方法不会执行因为对话框是activity 的一部分。

所以:构造对话框的Builder(context),这个context 是指定这个对话框挂载在哪个activity 上只能是activity.this获取的是子类的activity,当前activity context

不能是getApplicationContext(),整个应用程序的上下文

因为getApplicationContext 获取的是父类的activity而子类有的东西,父类不一定有。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: