[安卓基础]学习第七天

来源:互联网 发布:机器人运动仿真软件 编辑:程序博客网 时间:2024/05/22 02:05

一、为什么需要广播接收者(broadcastReceiver)

1.有什么样的人员听广播 老人,出租车司机2.听广播必须:电台,收音机,调频道3.Android内部已经定义好了电台,已经定义好了一些广播事件,如外拨电话,短信到来等等4.使用broadcastReceiver去接收系统定义好的这些事件5.javame javase javaee6.定义广播接收者目的是为了方便安卓开发者开发

二、案例

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.有序和无序广播的区别

  1. 无序广播不可以被终止,调用abortBroadcast()会在日志文件中打印警告
  2. 无序广播数据不可以修改

五、特殊广播接收者

操作特别频繁的广播事件,比如屏幕的锁屏和解锁,电池电量的变化。这种事件的广播在清单文件注册无效

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);
android:gravity和android:layout_gravity的区别在于前者对控件内部操作,后者是对整个控件操作