Android开发学习(广播)

四大组件之广播

在这里插入图片描述

1、监听电量变化状态(例子)

第一步:首先,我们创建一个Receiver类:

package com.sunofbeaches.broadcastreceiverdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * Created by TrillGates on 2018/3/15.
 */

public class BatteryStatusReceiver extends BroadcastReceiver {
    private static final String TAG = "BatteryStatusReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "action is == " + action);
        if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
            Log.d(TAG, "电量改变了的广播...");
        } else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
            Log.d(TAG, "电池低电量广播...");
        } else if (action.equals(Intent.ACTION_BATTERY_OKAY)) {
            Log.d(TAG, "电池充电完成。...");
        }
    }
}

上面的代码呢,是继承自己一个广播接收者BroadcastReceiver,这就类似于这个就是我们的收音机了,我们收听的频道是什么呢?由这个Action定,在那里添加Action频道呢?

这就是第二步:

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

权限在那里添加呢?在AndroidManifest.xml配置文件里,如图所示:
在这里插入图片描述
第三步,我们在ManiActivity里注册一下:

package com.sunofbeaches.broadcastreceiverdemo;

import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private BatteryStatusReceiver mReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter intentFilter = new IntentFilter();
        //设置频道,也就是设置要监听的广播action.
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        intentFilter.addAction(Intent.ACTION_BATTERY_OKAY);
        intentFilter.addAction(Intent.ACTION_BATTERY_LOW);
        //也可以监听usb的插拔
        mReceiver = new BatteryStatusReceiver();
        //注册广播
        registerReceiver(mReceiver, intentFilter);
        Log.d(TAG, "register receive..");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消广播注册,释放资源
        if (mReceiver != null) {
            unregisterReceiver(mReceiver);
            mReceiver = null;
            Log.d(TAG, "unregister receive..");
        }
    }
}

上面这代码的意思就是我们需要注册一下这个广播接收者,有没有觉得它中回调有点类似呢?但是我们是有条件地接受广播。这其实就类似于我们的收音机需要设置一个频道,收到这个频道的相关广播。而我们广播则是设置action,接下来的话,我们就把这个应用跑起来看看能不能接收到广播。我们监听着Android手机的电量变化情况

运行:

我们把这个程序跑起来,然后通过模拟器去模拟电量的变化,然后就可以收到了电量改变的广播了…

要注意的地方:

我们的应用要跑在前台哦,因为我们是动态注册广播接收者。我们的Activity创建的时候,会注册,在onDestroy的时候会取消注册。所以我们要保持这个我们的这个应用活着(返回键可以退出程序,前提是没有复写onBackPress事件/onKeyEvent方法)才可以接收到广播。

分步骤的代码:

package com.example.qqlogindemo.Broadcast;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import com.example.qqlogindemo.R;

public class BroadcastActivity extends Activity {

    private static final String TAG = "BroadcastActivity";
    BatteryStatusReceiver mReceiver;

    TextView power;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        initView();
        registerBatteryReceiver();

    }

    private void registerBatteryReceiver() {
        //第二步,新建意图过滤,收听的频道是:电量变化。
        IntentFilter intentFilter = new IntentFilter();
        //第三步,设置频段
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        //第四步
        mReceiver = new BatteryStatusReceiver();
        //第五步,注册广播,这种方式是动态注册
        this.registerReceiver(mReceiver, intentFilter);
    }

    private void initView() {
        power = (TextView)this.findViewById(R.id.power);
    }


    /**
     * 第一步:就是创建一个广播接收者,继承BroadcastReceiver(广播接收类),实现onReceive回调方法。
     */
    private class BatteryStatusReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "action is == " + action);
            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                Log.d(TAG, "电量改变了的广播...");
                //获取到电量的值
                int intExtra = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
                Log.d(TAG, "电量为..."+intExtra);
                //TextView,展示电量
                power.setText("电量数值是:"+intExtra);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消广播注册,否则会出现内存泄露问题(调用unregisterReceiver)
        if (mReceiver != null) {
            this.unregisterReceiver(mReceiver);
            mReceiver = null;
            Log.d(TAG, "unregister receive..");
        }
    }
}

在这里插入图片描述

2、广播的注册方式

广播有两种方式注册:静态注册和动态注册。

1.动态注册

监听电量变化状态(例子)就是属于一个动态注册。
动态注册的例子前面也有,这里的话,我们写别的例子吧!多写点例子,让同学们更熟悉广播的注册。注意,是广播的注册!!!后面我们才讲到广播的发送!

假设我们做一个地图软件 ,当我们知道屏幕锁定以后,那么就不去更新数据,如果是屏幕打开了,就去更新数据。为什么要这么做呢,一是省电,二是省流量,对吧!

怎么做呢?

首先,我们编写一个广播接收者:

我是在MainActivity这个类里头创建了这个广播接收者,一般来说,动态接收的广播多数情况下是内部类,这样子可以操作外部类。

private class ScreenStatusReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                //屏幕关闭
                Log.d(TAG, "屏幕关闭...停止数据更新");
            } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                //屏幕打开
                Log.d(TAG, "屏幕关闭...继续数据更新");
            }
        }
    }

接着呢,就是注册广播了:

我在onCreate方法里进行注册:

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

        //注册广播
        //第一步,创建意图过滤器
        IntentFilter intentFilter = new IntentFilter();
        //第二步,添加要监听的广播action
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        //第三步,创建广播接收者,并且设置成成员变量,以便于取消注册,释放资源
        mScreenStatusReceiver = new ScreenStatusReceiver();
        //第四步,注册广播接收者
        this.registerReceiver(mScreenStatusReceiver, intentFilter);
    }

广播注册以后,要记得在不用的时候进行销毁,这个应用于对我们来说,就是在退出的时候,我们就不需要地广播进行监听了,所以我们直接在onDestroy的时候,去取消注册即可。

 @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消广播注册
        if (mScreenStatusReceiver != null) {
            this.unregisterReceiver(mScreenStatusReceiver);
            mScreenStatusReceiver = null;
        }
    }

好啦,以下是整个代码:

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private ScreenStatusReceiver mScreenStatusReceiver;

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

        //注册广播
        //第一步,创建意图过滤器
        IntentFilter intentFilter = new IntentFilter();
        //第二步,添加要监听的广播action
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        //第三步,创建广播接收者,并且设置成成员变量,以便于取消注册,释放资源
        if (mScreenStatusReceiver == null) {
            mScreenStatusReceiver = new ScreenStatusReceiver();
        }
        //第四步,注册广播接收者
        this.registerReceiver(mScreenStatusReceiver, intentFilter);
    }

    private class ScreenStatusReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                //屏幕关闭
                Log.d(TAG, "屏幕关闭...停止数据更新");
            } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                //屏幕打开
                Log.d(TAG, "屏幕关闭...继续数据更新");
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消广播注册
        if (mScreenStatusReceiver != null) {
            this.unregisterReceiver(mScreenStatusReceiver);
            mScreenStatusReceiver = null;
        }
    }
}

接收这个广播不需要权限,大家怎么知道是否需要权限呢?比如说前面我们写的例子,监听开机广播。我们可以在android studio里敲出:Intent.ACTION_BOOT_COMPLETED,然后点击进去看看:

/**
     * Broadcast Action: This is broadcast once, after the user has finished
     * booting. It can be used to perform application-specific initialization,
     * such as installing alarms. You must hold the
     * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
     * order to receive this broadcast.
     * <p>
     * This broadcast is sent at boot by all devices (both with and without
     * direct boot support). Upon receipt of this broadcast, the user is
     * unlocked and both device-protected and credential-protected storage can
     * accessed safely.
     * <p>
     * If you need to run while the user is still locked (before they've entered
     * their lock pattern or PIN for the first time), you can listen for the
     * {@link #ACTION_LOCKED_BOOT_COMPLETED} broadcast.
     * <p class="note">
     * This is a protected intent that can only be sent by the system.
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";

{@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in order to receive this broadcast.

这句话的意思就是,你需要这个权限”android.permission.RECEIVE_BOOT_COMPLETED”

目的是为接收这个广播,否则你接收不到。

一般来说,在我们的action里会说明,如果以后,你自己写广播,在自己的action里也要说明一下需要什么权限了。

2.静态注册

1、注册方式:在AndroidManifest里进行注册。

首先在Application节点里头,添加一个receiver节点。name则是我们的广播接收者。

比如说,我们监听开机广播,那么我们跟前面一样,创建一个收音机,也就是广播接收者:

package com.sunofbeaches.broadcastreceiverdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * Created by TrillGates on 2018/3/15.
 */

public class BootCompletedReceiver extends BroadcastReceiver {

    public static final String TAG = "BootCompletedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "actions -- >" + action);
        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
            Log.d(TAG, "开机完成");
        }
    }
}

接着,这就是静态注册了,在AndroidMainfest.xml里的application节点里添加receiver节点,并且添加意图过滤的action:

<receiver android:name=".BootCompletedReceiver">
           <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
           </intent-filter>
</receiver>

并且需要添加权限:
在这里插入图片描述
把程序跑起来,这个是静态注册,即使我们写的应用不在前台,也能接收到广播。这是静态注册的特点。

静态注册内部类广播要注意什么呢?

首先是静态注册,其次是内部广播接收者!

1、这个内部广播接收者需要声明为静态的;

2、这个内部的静态接收者必须是public的;

3、在receiver的name里是外部类的名字$内部类的名字

这就是静态注册方式啦!
在这里插入图片描述

3.两种注册方式的区别

静态注册可以一直监听着,即使应用没有起来,也可以监听着,但是耗资源,长期监听着。

静态注册的广播优先级高于动态注册的广播。

动态注册的优点就是省资源,需要的时候才监听,不需要的时候需要取消注册。

3、监听到程序是否安装或者卸载成功

许多时候,需要监听到程序是否安装或者卸载成功,在android系统中,安装和卸载都会发送广播,当应用安装完成后系统会发android.intent.action.PACKAGE_ADDED广播。可以通过intent.getDataString()获得所安装的包名。当卸载程序时系统发android.intent.action.PACKAGE_REMOVED广播。同样intent.getDataString()获得所卸载的包名。

所以,只需要自定义一个BroadcastReceiver,来对系统广播进行监听和处理。

1、自定义广播
自定义广播MyInstalledReceiver继承自BroadcastReceiver,实现其onReceive()方式,具体代码如下:

import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
 
public class BootReceiver extends BroadcastReceiver{ 
       
    @Override   
    public void onReceive(Context context, Intent intent){ 
        //接收安装广播  
        if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {    
            String packageName = intent.getDataString();    
            System.out.println("安装了:" +packageName + "包名的程序");      
        }    
        //接收卸载广播   
        if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {    
            String packageName = intent.getDataString();    
            System.out.println("卸载了:"  + packageName + "包名的程序"); 
  
        } 
    } 
} 

2、注册监听

XML配置方式:在AndroidManifest.xml 配置文件的Application节点下,添加自定义的注册监听 MyInstalledReceiver,在AndroidManifest.xml 添加的注册监听,其生命周期默认是整个应用的生命周期。

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.apk" 
    android:versionCode="1" 
    android:versionName="1.0" > 
 
    <application 
        android:icon="@drawable/ic_launcher" 
        android:label="@string/app_name" > 
        <activity 
            android:name=".MainActivity" 
            android:label="@string/app_name" > 
            <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
        </activity> 
 
        <receiver android:name=".MyInstalledReceiver" > 
            <intent-filter> 
                <action android:name="android.intent.action.PACKAGE_ADDED" /> 
                <action android:name="android.intent.action.PACKAGE_REMOVED" /> 
 
                <data android:scheme="package" /> 
            </intent-filter> 
        </receiver> 
    </application> 
    <uses-sdk android:minSdkVersion="3" /> 
</manifest> 

代码方式:一般在Activity的onStart()方法中注册监听,在onDestroy()方法中注销监听(也可以在onStop()方法中注销,其生命周期注销时结束)

@Override 
public void onStart(){ 
    super.onStart(); 
     
     //自己创建的类
    installedReceiver = new MyInstalledReceiver(); 
    IntentFilter filter = new IntentFilter(); 
     
    filter.addAction("android.intent.action.PACKAGE_ADDED"); 
    filter.addAction("android.intent.action.PACKAGE_REMOVED"); 
    filter.addDataScheme("package"); 
     
    this.registerReceiver(installedReceiver, filter); 
} 
 
@Override 
public void onDestroy(){ 
    if(installedReceiver != null) { 
        this.unregisterReceiver(installedReceiver); 
    } 
     
    super.onDestroy(); 
} 

3、存储安装、卸载信息

一般时候,需要使用到程序的安装、卸载信息,所以需要将信息存储起来,比较好的方式是使用Sqlite数据库,也可以使用首选项等。

4、发送自定义广播

前面的话我们都是接收系统发出来的广播,接下来我们自己也发广播。

假设你做一个应用,比较牛逼一点的,对吧!需要对多进行通知。做这类应用有两种情况:

第一种是做sdk开发的,也就是开发sdk给别人使用的。

第二种是应用内广播,其实就是通知。

PS:额外的知识,我们学习android的广播机制有什么用呢,其实就是用于通知。如果在应用内,我们常用的通知方式是回调和广播。这两者之前,回调的速度快,保障性高,而广播则简单,但是速度没有回调高。什么情况下使用广播呢?当有多个地方使用等待通知的时候,可以使用广播。原理上广播和回调差不多的,广播的原理就是使用Binder机制,把action注册到ActivityManagerService里头,然后广播的时候,就去里面寻找符合规则的,再调用onReceive这个方法。

另外一种情况就是跨进程通讯,后面我们会学习到AIDL,这里的话是广播。广播是可以跨应用通知的,比如我们接收到了系统的广播对吧!也可以进行权限的控制,谁可以接收到这样的广播。

好,回到我们的主题,怎么样发送广播呢?

我们先不讨论发送有序广播,我们就随随便便发个广播通知!

这个是我们的布局文件,就一个按钮,我们点击按钮的时候,就去发送广播。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="sendBroadcast"
        android:text="发送广播"/>

</LinearLayout>

以下是Activity的内容,从代码看出我们是怎么发送广播的:

package com.sunofbeaches.broadcastdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class SendBroadcastActivity extends Activity {

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

    }

    public void sendBroadcast(View view) {
        Intent intent = new Intent();
        //action只能有一个,所以叫setAction而不是addActon。
        //而广播接收者可以监听多个广播,所以是addAction
        //action的命名一般是报名+动作名,这样子比较唯一
        intent.setAction("com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK");
        //也可以携带数据
        intent.putExtra("Content", "这是我点击按钮发送的广播!");
        sendBroadcast(intent);
    }
}

然后呢,我们再写一个广播接收者来接收广播,这个接收者可以是在第三方应用,也可以在我们本应用,我们写一个静态注册来注册它。前面已经教过大这怎么编写广播接收者了,并且怎么注册。这里的话我们写一个内部类来接收。前面说到了,要注意的是,内部广播接收者类,需要是静态的,Public的,注册的时候,是外部类名$内部类名

package com.sunofbeaches.broadcastdemo;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class SendBroadcastActivity extends Activity {

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

    }

    public void sendBroadcast(View view) {
        Intent intent = new Intent();
        //action只能有一个,所以叫setAction而不是addActon。
        //而广播接收者可以监听多个广播,所以是addAction
        //action的命名一般是报名+动作名,这样子比较唯一
        intent.setAction("com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK");
        //也可以携带数据
        intent.putExtra("Content", "这是我点击按钮发送的广播!");
        sendBroadcast(intent);
    }

    public static class InnerReceiver extends BroadcastReceiver{

        private static final String TAG = "InnerReceiver";

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "Inner receiver 接收到的actions... " + action);
            if ("com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK".equals(action)) {
                String content = intent.getStringExtra("Content");
                Log.d(TAG, "content is == " + content);
            }
        }
    }
}

静态注册的代码:

<receiver android:name=".SendBroadcastActivity$InnerReceiver">
      <intent-filter>
           <action android:name="com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK"/>
      </intent-filter>
</receiver>

然后我们设置一下 这个Activity是主的Activity,也就是启动时候,它先启动。
这就是我们自定义的广播发送者和广播接收者啦!

5、有序广播

前面我们所讲到的都是无须广播,也就是发出去了,任何应用都可以接收到,只要有对应的Action就可以了。

有序广播:有序广播就类似于单位的通知,由上级一级一级往下传。特点是:
1、有序

2、可以终止往下传达

3、可以修改广播的内容

以一个例子来说明吧:

假设学校收到一笔捐款,用于资助各年级各班的贫困学生。

于是:我们有一个广播发送者叫做xxx基金会,给每个贫困学生发送1000块钱的资助金。

布局跟前面一样,只有一个按钮:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:onClick="sendDonation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送捐助广播"/>

</LinearLayout>

然后呢,是Activity的代码,怎么样去发送有序广播!

package com.sunofbeaches.broadcastdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class DonationBroadcastActivity extends Activity {

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

    public void sendDonation(View view) {
        Intent intent = new Intent();
        intent.setAction("com.sunofbeaches.broadcastdemo.DONATION");
        Bundle bundle = new Bundle();
        bundle.putInt("money", 1000 * 500);
        sendOrderedBroadcast(intent, null, null, null, 1, "给每个贫困的学生资助1000元", bundle);
    }

}

这里怎么简单怎么样,关于权限的问题后面我们再解释。先给大家解释一下,每个参数是什么意思先!

@Override
    public void sendOrderedBroadcast(
        Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
        Handler scheduler, int initialCode, String initialData,
        Bundle initialExtras) {
        mBase.sendOrderedBroadcast(intent, receiverPermission,
                resultReceiver, scheduler, initialCode,
                initialData, initialExtras);
    }

上面这个是原方法:

  • 第一个参数,不用说了,我们发送广播就知道了,这个是意图对象,用于封装数据和设置过滤。
  • 第二个参数是权限,权限我们后面会详细说到,虽然很少用到,但是你知道这个思想,有利于你以后自己钻研android的代码。
  • 第三个参数是广播接收者,这个广播接收者是最终接收的广播接收者,用于检查数据是否有传达或者数据被修改。
  • 第四个参数是一个自定义的Hanlder,用于处理结果接收者,也就是上面那个接收者的回调。
  • 第五个参数是初始码,这个会作为结果码,通常是Activity.RESULT_OK,也就是-1。
  • 第六个参数是用于传递数据的,这个数据在各个Receiver里获取到,通过getResultData方法获取。这个其实通常为null
  • 第七个参数也是用于封装数据的,不同的是,这个用于封装数据集合,从上面的代码可以知道 ,我用来封装了一个钱的数据。

以下是原api的说明文档:
在这里插入图片描述
写完了发送者以后,我们就会去写一下接收者了。

三个接收者的代码如下,分别是学校接收者,年级接收者,班级接收者,贫困这生接收者!

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class SchoolReceiver extends BroadcastReceiver {
    private static final String TAG = "SchoolReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle resultExtras = getResultExtras(true);
        int money = resultExtras.getInt("money");
        //学校处理一下,分给5个年级
        int perGrade = money / 5;
        Log.d(TAG, "学校接收到捐款 " + money);
        Bundle bundle = new Bundle();
        bundle.putInt("money", perGrade);
        setResultExtras(bundle);
    }
}

年级广播接收者:

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class GradeReceiver extends BroadcastReceiver {
    private static final String TAG = "GradeReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle resultExtras = getResultExtras(true);
        //假设每个年级有10个班
        resultExtras.putInt("money", resultExtras.getInt("money") / 10);
        Log.d(TAG, "年级收到捐款 " + resultExtras.getInt("money"));
    }
}

班级接收者:

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class ClassReceiver extends BroadcastReceiver {
    private static final String TAG = "ClassReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle resultExtras = getResultExtras(true);
        //假设每个班有10个贫困的孩子
        int perStudent = resultExtras.getInt("money")/10;
        Log.d(TAG, "班级收到捐款--> " + resultExtras.getInt("money"));
        Bundle bundle = new Bundle();
        bundle.putInt("money", perStudent);
        setResultExtras(bundle);
    }
}

贫困学生接收者:

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class PoorStudentReceiver extends BroadcastReceiver {
    private static final String TAG = "PoorStudentReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle resultExtras = getResultExtras(true);
        int money = resultExtras.getInt("money");
        Log.d(TAG, "接收到捐款 --> " + money);
        Log.d(TAG, "感谢各位好心人士...");
    }
}

广播也写好了,那么就是注册广播了:

在AndroidManifest.xml文件里头;

<receiver android:name=".SchoolReceiver">
    <!--优先级是1000~-1000之间,超出了范围则会使用边界值-->
    <intent-filter android:priority="1000">
        <action android:name="com.sunofbeaches.broadcastdemo.DONATION"/>
    </intent-filter>
</receiver>

<receiver android:name=".GradeReceiver">
    <intent-filter android:priority="500">
        <action android:name="com.sunofbeaches.broadcastdemo.DONATION"/>
    </intent-filter>
</receiver>


<receiver android:name=".ClassReceiver">
    <intent-filter android:priority="100">
        <action android:name="com.sunofbeaches.broadcastdemo.DONATION"/>
    </intent-filter>
</receiver>


<receiver android:name=".PoorStudentReceiver">
    <intent-filter android:priority="-1000">
        <action android:name="com.sunofbeaches.broadcastdemo.DONATION"/>
    </intent-filter>
</receiver>

关于优先级的说明在注释里已经有了priority就是优先级的意思。

那我们就把程序跑起来吧,看谁先接收到广播:
在这里插入图片描述
好啦,从上面的例子,我们可以看到,广播是按优先级通知的,并且可以修改广播的内容。

终止广播的传达

也可以终止广播的传达,假设这笔捐款到了学校就不往下传了,怎么处理呢?

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class SchoolReceiver extends BroadcastReceiver {
    private static final String TAG = "SchoolReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle resultExtras = getResultExtras(true);
        int money = resultExtras.getInt("money");
        //学校处理一下,分给5个年级
        int perGrade = money / 5;
        Log.d(TAG, "学校接收到捐款 " + money);
        Bundle bundle = new Bundle();
        bundle.putInt("money", perGrade);
        setResultExtras(bundle);
        //终止广播往下传
        abortBroadcast();
    }
}

abortBroadcast(),我们加了这句代码,运行结果如下:
在这里插入图片描述
说明不会再往下传递了。

6、广播的权限

前面我们有提到权限,但是我们一笔略过,到这里才对权限进行分析。广播的权限分为两部分,一部分是我可以接收谁的广播,一部分是谁可以给我发广播。这就是权限啦!

1.我发的广播谁可以接收到

如果要做到我发的广播,有权限的人才能接收到,那么需要这样做:

在AndroidManifest.xml中生命permission

< permission android:name=“com.sunofbeaches.permission.DONATION”/>

发送广播的时候把permision加上,比如说:

    public void sendDonation(View view) {
        Intent intent = new Intent();
        intent.setAction("com.sunofbeaches.broadcastdemo.DONATION");
        Bundle bundle = new Bundle();
        bundle.putInt("money", 1000 * 500);
        sendOrderedBroadcast(intent, Manifest.permission.DONATION, null, null, 1, "给每个贫困的学生资助1000元", bundle);
    }

Manifest.permission.DONATION这一句其实就是我们前面定义的权限,按Control点击可以跳过去。
第三步则是在需要接收的应用里头,添加权限,因为我们这里是同一个应用,所以在本应用添加就可以了:

< uses-permission android:name=“com.sunofbeaches.permission.DONATION”/>

这样子就可以接收到广播了!

2.谁有权限给我发广播

谁有权限给我发广播,这个其实在receiver的节点里头,就有一个permission的属性
在这里插入图片描述
这个Permission声明就是用于控制谁有权限给我发广播的。
图解:
接收广播的AndroidManifest.xml
在这里插入图片描述
发送广播的AndroidManifest.xml要添加接收广播自定义的权限。

< uses-permission android:name=“com.sunofbeaches.broadcastpermissiondemo.WHO_CAN_SEND_2_ME”/>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值