Android基础知识——详解广播机制

1.广播机制简介

当android手机的状态发生变化时,系统就会发送一条广播,而开发者则可以自定义广播接收器来接受自己所需的广播,从而执行一些逻辑代码(例如:当手机电量剩余15%时,提示用户是否进入省电模式),另外不止系统可以发送广播,开发者也可以自定义发送广播。

而广播则主要分为两种类型:标准广播,有序广播。

标准广播:一种完全异步执行的广播,在广播发送后,所有的广播接收器都会在同一时刻接收到这条广播,没有任何先后顺序可言。但也同时意味着它是无法被截断的。

有序广播:一种同步执行的广播,在广播发送后,同一时刻只会有一个广播接收器能收到这条广播消息,当这个广播接收器中的逻辑执行完毕后才会继续传递。所以这种类型的广播是有先后顺序的,并且前面的广播接收器还可以截断正在传递的广播。

2.接受系统广播

注册广播的方式有两种。在代码中注册和在AndroidManifest.xml中注册,其中前者也称作动态注册,后者也被称为静态注册。

2.1动态注册广播

使用步骤:

1.创建类继承BroadcastReceiver类,并重写onReceive()方法,在其中加入接收到广播后的逻辑。
2.获取IntentFilter实例,并调用addAction()方法,为IntentFilter设置想要接收到的广播信息。
3.获取新建类的实例,再调用reregisterReceiver(BroadcastReceive类的实现类,IntentFilter实例)方法为该广播进行注册。
4.所有动态注册的广播最后都应该调用unreregisterReceiver(BroadcastReceive类的实现类)方法取消注册。

示例:

public class MainActivity extends AppCompatActivity {
    
    
    MyBroadcastReceiver receiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=(Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                IntentFilter filter=new IntentFilter();//步骤二
                filter.addAction("你需要接收的广播内容");
                receiver=new MyBroadcastReceiver();//步骤三
                registerReceiver(receiver,filter);
            }
        });
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        unregisterReceiver(receiver);//步骤四
    }

    class MyBroadcastReceiver extends BroadcastReceiver{
    
    //步骤一
        @Override
        public void onReceive(Context context, Intent intent) {
    
    
            //接收到广播后的逻辑代码
        }
    }
}

2.2静态广播注册

动态注册的广播在灵活性方面有很大优势,不过它也存在着一个缺点,即必须要在程序启动后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。那么怎样在程序未启动的情况下就能接收到广播呢?

静态注册就可以很好的解决这个问题了。

使用步骤:

1.创建一个广播接收器,As会自动帮我们生成一个继承BroadcastReceiver的类并帮我们在AndroidManifest.xml中进行注册。
2.在新生成类的onReceive()方法中加入接收到广播后的逻辑代码。
3.在AndroidManifest.xml中注册的receiver下加入< intent-filter >再在其中加入标签<cation android:name >用于设置你想要收到的广播信息。

示例:

//步骤一:略
//步骤二
public class MyReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        //接收到广播后的逻辑代码
    }
}
//步骤三
<receiver
     android:name=".MyReceiver"
     android:enabled="true"
     android:exported="true">
     <intent-filter>
          <action android:name="你需要接收的广播内容" />
     </intent-filter>
</receiver>

3.发送自定义广播

广播主要分为两种类型:标准广播,有序广播。我们接下来就来学习如何发送自定义的这两种广播。

3.1发送标准广播

使用步骤:

1.获取Intent示例,创建实例时在构造器中加入你想要发出的广播消息。
2.调用intent.setPackage(广播接收器的包名)方法为广播指明方向。(android8.0以后且广播接收器是静态注册的才需要这步操作)
3.调用sendBroadcast(Intent)方法发送标准广播。

示例:

 Intent intent=new Intent("com.example.temp02.MY_BROADCAST");//步骤一
 intent.setPackage("com.example.temp02");//步骤二
 sendBroadcast(intent);//步骤三

3.2发送有序广播

使用步骤:

1.获取Intent示例,创建实例时在构造器中加入你想要发出的广播消息。
2.调用intent.setPackage(广播接收器的包名)方法为广播指明方向。(android8.0以后且广播接收器是静态注册的才需要这步操作)
3.调用sendOrderedBroadcast(Intent,null);方法发送有序广播。

示例:

 Intent intent=new Intent("com.example.temp02.MY_BROADCAST");//步骤一
 intent.setPackage("com.example.temp02");//步骤二
 sendOrderedBroadcast(intent,null);//步骤三

那么怎样设置有序广播的接收顺序呢?

答:只需在广播接收器的< intent-filter >标签里加入android:priority属性给广播接收器设置优先级即可,优先级较高的广播接收器会先接收到广播(最大值为100)。

那么前面的广播接收器怎样截断正在传递的广播呢?

答:只需在广播接收器的onReceive()方法中加入abortBroadcast()方法即可截断该广播,使其优先级之后的广播接收器不能再接收到该广播。

4.使用本地广播

前面我们发送和接收的广播全部属于全局广播,即发出的广播可以被其它任何应用程序接收到,并且我们也可以收到来自其它任何应用程序的广播。这样就很容易引起安全问题,比如我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其它程序不停的向我们的广播接收器里发送各种垃圾广播。

为了能够解决这一安全问题,Android引入了一套本地广播机制,使用这个机制发送的广播只能在本应用程序内进行传递,并且广播接收器也只能接收来自本地应用程序发出的广播。

使用步骤:
与全局广播的使用步骤是一致的,不过需要获得LocalBroadcastManager实例,用其对发送广播,注册和注销广播接收器进行管理。

示例:

public class MainActivity extends AppCompatActivity {
    
    
    LocalBroadcastManager manager;
    MyReceiver receiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=(Button) findViewById(R.id.button);
        manager =LocalBroadcastManager.getInstance(MainActivity.this);//获取LoaclBroadcastManager实例
        button.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent("com.example.temp02.MY_BROADCAST");
                manager.sendBroadcast(intent);//用manager对发送进行管理
            }
        });
        IntentFilter filter=new IntentFilter();
        filter.addAction("com.example.temp02.MY_BROADCAST");
        receiver=new MyReceiver();
        manager.registerReceiver(receiver,filter);//用manager对注册广播进行管理
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        manager.unregisterReceiver(receiver);//用manager对注销广播进行管理
    }

    class MyReceiver extends BroadcastReceiver{
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
    
            Toast.makeText(MainActivity.this,"ok",Toast.LENGTH_SHORT).show();
        }
    }
}

另外还需要说明一点,本地广播是无法通过静态注册的方式来接收的,因为静态注册主要就是为了让程序在未启动的情况下也能接受到广播,而发送本地广播时,我们的程序肯定已经启动了,因此也就完全不需要使用静态注册的功能。

5.一些其它问题

5.1关于android8.0以后广播无法跨程序接收的问题

在android8.0以后,安卓对广播的使用设置了很多限制,以防止其产生安全问题。正如我们在3.1中介绍的那样,android8.0以后且广播接收器是静态注册时,就需要给广播设置一个包名为其指明方向,否则即使是在同一个程序中你自定义的广播也不会被接收到。而在android8.0以后并且无论另一个程序的广播接收器是以何种方式注册来的,当你需要跨程序发送广播时,你也需要为你的广播指明方向,否则你的广播是无法被其它程序接收到的。

示例:

Intent intent=new Intent("com.example.temp02.MY_BROADCAST");
intent.setPackage("com.example.temp02");//指向本程序中的广播接收器
sendBroadcast(intent);
intent.setPackage("com.example.temp");//指向其它程序中的广播接收器
sendBroadcast(intent);

5.2利用广播传递数据的问题

广播不仅可以发出一条表示某些状态改变的信息,我们还可以调用intent的putExtra()方法让广播在发送时携带一些数据。同理我们可以在广播接收器的onReceive()方法中获得这些数据

示例:

public class MainActivity extends AppCompatActivity {
    
    
    MyReceive receive;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=(Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent("com.example.temp02.MY_BROADCAST");
                intent.putExtra("data","hhhhhh");
                sendBroadcast(intent);
            }
        });
        IntentFilter filter=new IntentFilter();
        filter.addAction("com.example.temp02.MY_BROADCAST");
        receive=new MyReceive();
        registerReceiver(receive,filter);
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        unregisterReceiver(receive);
    }
    
    class MyReceive extends BroadcastReceiver{
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
    
            Toast.makeText(context,intent.getStringExtra("data"),Toast.LENGTH_SHORT).show();
        }
    }
}

5.3使用广播时的注意事项

当我们使用广播时需要注意的是,不要在onReceive()方法中添加过多的逻辑或者进行任何耗时的操作,因为在广播接收器中是不允许开启线的,当onReceive()方法运行了较长时间而没有结束时,程序就会报错。因此广播接收器更多的是扮演一种打开程序其它组件的角色,比如创建一条状态通知栏,或者启动一个服务等。

猜你喜欢

转载自blog.csdn.net/ABded/article/details/108236203
今日推荐