学习《第一行代码》(九)


PS:跳过了第四章(探究碎片),是平板的相关内容

1.广播类型
类型区别备注
标准广播完全异步执行,所有广播接收器同时收到广播消息效率较高但无法被截断
有序广播同步执行,按广播接收器的优先级传递消息可截断
2.接受系统广播
动态注册——在代码中

(必须在程序启动后才能接收广播)
举例:监听网络状态变化

public class EightActivity extends AppCompatActivity {

    private IntentFilter intentFilter ;
    private NetworkChangeReceiver networkChangeReceiver ;
    int times = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_eight);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        //网络发生变化时会发出一条值为android.net.conn.CONNECTIVITY_CHANGE的广播
        
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
        //调用registerReceiver进行注册
    }

    @Override
    protected void onDestroy(){
    //动态注册的广播接收器一定要取消注册,所以在活动销毁时调用unregisterReceiver
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver{
	//每当网络发生变化时,onReceive会得到执行
        @Override
        public void onReceive(Context context, Intent intent){
            TextView textView = (TextView) findViewById(R.id.Eight_TextView);
            Toast.makeText(context,"Network changes",Toast.LENGTH_SHORT).show();
            textView.setText("网络改变了"+ ++times +"次");
        }
    }
}

效果:

说明一下,最开始显示是1次因为打开监听是从无网络到有网络,所以是一次,然后打开WiFi显示改变了3次,我用真机测试了一下发现是因为打开WiFi是先断开数据连接(1次),再连接WiFi(1次),所以是1+1+1=3次

改写一下onReceive使得可以提示网络是断开还是连接

class NetworkChangeReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent){
        ConnectivityManager connectivityManager =(ConnectivityManager) 
        									getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isConnected()){
            Toast.makeText(context,"网络已连接",Toast.LENGTH_SHORT).show();
        }
        else {
            Toast.makeText(context,"网络已断开",Toast.LENGTH_SHORT).show();
        }
        TextView textView = (TextView) findViewById(R.id.Eight_TextView);
        textView.setText("网络改变了"+ ++times +"次");
    }
}

效果:

(由于用的虚拟机是Android9.0,真的卡)

此外《第一行代码》中提示说,访问系统的网络状态需要声明权限,在AndroidManifest.xml中加入:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
静态注册实现开机启动——在AndroidManifest.xml中

(Android 9.0我实现不了,于是下了7.0来测试,搜索了一波发现说是因为8.0版本开始已经不支持大部分的静态注册)
①右键 com.example.activitytest -->New -->Other -->Broadcast Receiver
在这里插入图片描述

命名为BootCompleteReceiver
Alt text

加一条信息提示用于测试:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class BootCompleteReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Toast.makeText(context, "开机启动", Toast.LENGTH_SHORT).show();
        //throw new UnsupportedOperationException("Not yet implemented");
    }
}

②AndroidManifest.xml

<receiver
    android:name=".BootCompleteReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

③同样的,需要声明权限

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

④效果

3.发送自定义广播
发送标准广播

经过测试发现收不到广播,于是搜索了一波发现

8.0版本开始已经不支持大部分的静态注册的广播(隐式发送的)了

解决方法:

  • 换成7.0以下版本的虚拟机
  • 用显示方法发送广播

①先定义广播接收器

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        //throw new UnsupportedOperationException("Not yet implemented");
        Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
    }
}

②修改AndroidManifest.xml
(如果是用显示方法发送广播,这一步改不改都可以,我猜测可能是因为显示发送广播指定了广播接收器的缘故)

<receiver
    android:name=".MyBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.ActivityTest.MY_BROADCAST" />
    </intent-filter>
</receiver>

③添加按钮负责发广播消息
如果是显示发送的广播,可以不设置action,即使设置了action也会被忽略

public class EightActivity extends AppCompatActivity {
    private IntentFilter intentFilter ;   
    private MyBroadcastReceiver myBroadcastReceiver;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_eight);
        Button button = (Button) findViewById(R.id.Send_Broadcast);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
				Intent intent = new Intent("com.example.ActivityTest.MY_BROADCAST");
		        //Intent intent = new Intent();
		        //intent.setComponent(new ComponentName(EightActivity.this,MyBroadcastReceiver.class));
		        sendBroadcast(intent);
            }
        });
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(myBroadcastReceiver);
        unregisterReceiver(anotherBroadcastReceiver);
    }

④效果:

发送有序广播

即按Receiver的优先级接收广播,优先级高的先接收,可以中间截断
在发送标准广播的基础上修改:
①Activity中:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_eight);
        Button button = (Button) findViewById(R.id.Send_Broadcast);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.ActivityTest.MY_BROADCAST");
                sendOrderedBroadcast(intent,null);
                //这里的null可以替换成与权限相关的字符串
            }
        });
    }

②设置Receiver的优先级:这里设成MyBroadcastReceiver比AnotherBroadcastReceiver优先级高

<receiver
    android:name=".AnotherBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.ActivityTest.MY_BROADCAST" />
    </intent-filter>
</receiver>
<receiver
    android:name=".MyBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="100">
    //proiority设置优先级,优先级高的Receiver先收到广播
        <action android:name="com.example.ActivityTest.MY_BROADCAST" />
    </intent-filter>
</receiver>

③修改其中一个Receiver,使其在接收到广播后截断广播
abortBroadcast()即为截断广播的方法

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
        abortBroadcast();
    }
}

④不执行截断跟执行截断的效果:

4.发送本地广播
举例

用LocalBroadcastManager解决
修改活动中的代码即可:

public class EightActivity extends AppCompatActivity {

    private IntentFilter intentFilter ;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;

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

        localBroadcastManager = LocalBroadcastManager.getInstance(this);

        Button button = (Button) findViewById(R.id.Send_Broadcast);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.ActivityTest.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);
            }
        });
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.ActivityTest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
		unregisterReceiver(localReceiver)
    }

    class LocalReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            Toast.makeText(context,"收到本地广播",Toast.LENGTH_SHORT).show();
        }
    }

效果:

(其实代码与动态注册全局广播很相似,只是本地广播用了LocalBroadcastManager)

总结

书中给出了三点本地广播的优势:

可以明确的知道正在发生的广播不会离开程序,无需担心机密数据泄露
其他程序无法发送广播到程序内部,无需担心安全漏洞的隐患
发送本地广播比全局广播更高效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值