Broadcast 使用详解

极力推荐文章:欢迎收藏
Android 干货分享 java

阅读五分钟,每日十点,和您一块儿终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,经过阅读本篇文章,您将收获如下内容:android

  1. 广播的生命周期
  2. 四大组件之一,必须在Androidmainfest.xml中注册
  3. 广播的注册(静态广播、动态广播)
  4. 广播的发送(正常、有序、持续)
  5. 广播接收(系统广播、自定义广播)

Broadcast Android 四大组件之一,是一种普遍运用在应用程序之间异步传输信息的机制。
Broadcast 本质上是一个Intent 对象,差异在于 Broadcast 能够被多个 BroadcastReceiver 处理。BroadcastReceiver 是一个全局监听器,经过它的 onReceive() 能够过滤用户想要的广播,进而进行其它操做。程序员

1. BroadcastReceiver简介

BroadcastReceiver继承关系

BroadcastReceiver 默认是在主线程中执行,若是onReceiver() 方法处理事件超过10s,则应用将会发生ANR(Application Not Responding),此时,若是创建工做线程并不能解决此问题,所以建议:如处理耗时操做,请用 Service 代替。微信

BroadcastReceiver继承关系 以下:网络

java.lang.Object
   ↳    android.content.BroadcastReceiver

BroadcastReceiver 的主要声明周期方法onReceiver(),此方法执行完以后,BroadcastReceiver 实例将被销毁。并发

2.四大组件之一,必须在Androidmainfest.xml中注册

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

注意:
如不注册,将致使没法接收处理广播消息app

3.广播的注册(静态注册、动态注册)

广播的注册分两种,一种在ndroidMfest.xml中静态注册,另外一种是在Java代码中动态注册。异步

1.静态注册

一些系统发送的广播须要在Androidmainfest.xml 中静态注册,例如 开机广播,apk状态改变广播,电量状态改变广播等。这些静态注册的广播,一般在Androidmainfest.xml 中拦截特定的字符串。ide

静态注册广播的方法以下:学习

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.programandroid"
    android:versionCode="1"
    android:versionName="1.0" >
         ... ...
        <receiver
            android:name="com.programandroid.BroadcastReceiver.NotificationReceived"
            android:enabled="true"
            android:exported="true" >
            <intent-filter>
                <action android:name="Notification_cancel" />
                <action android:name="Notification_music_pre" />
                <action android:name="Notification_music_play" />
                <action android:name="Notification_music_next" />
            </intent-filter>
        </receiver>
        ... ...

1.静态注册开机广播方法

开机广播比较特殊,须要在Androidmainfest.xml 中添加权限。不然,没法获取开机广播。

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

//静态注册广播的方法
        <receiver
            android:name=".component.BroadcastReceiver.BootReceiverMethod"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

2.动态注册广播

在Java中动态注册广播,一般格式以下:

//动态注册广播
  registerReceiver(BroadcastReceiver, IntentFilter);

动态注册 监听灭屏、点亮屏幕的广播

在广播中动态注册广播请注意必定要使用context.getApplicationContext(),防止context 为空 ,引发空指针异常。

public class ScreenOnOffReceiver {

    public static void ReceiverScreenOnOff(Context context) {
        IntentFilter screenOffFilter = new IntentFilter();
        screenOffFilter.addAction(Intent.ACTION_SCREEN_OFF);
        screenOffFilter.addAction(Intent.ACTION_SCREEN_ON);
        BroadcastReceiver mScreenOnOffReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                // TODO Auto-generated method stub
                String action = intent.getAction();
                if (action.equals(Intent.ACTION_SCREEN_OFF)) {

                    Toast.makeText(context, "接收屏幕熄灭广播", Toast.LENGTH_SHORT).show();

                }
                if (action.equals(Intent.ACTION_SCREEN_ON)) {

                    Toast.makeText(context, "接收屏幕点亮广播", Toast.LENGTH_SHORT).show();
                }


            }

        };
        /**
         * context.getApplicationContext()
         * 在广播中注册广播时候须要注意,防止context 为空 ,引发空指针异常
         * **/
// 2.动态注册广播的方法
        context.registerReceiver(mScreenOnOffReceiver, screenOffFilter);

    }
}

4.广播的发送(无序、有序、持续)

1.发送无序广播的方法

发送无序广播在Android 中很常见,是一种一对多的关系,主要经过 sendBroadcast(intent);发送广播。

发送自定义广播案例

广播说白了就是一个带Action等字符串标记的Intent。发送自定义广播举例以下:

Intent customIntent=new Intent();
        customIntent.setAction("SendCustomBroadcast");
        sendBroadcast(customIntent);

接收自定义广播的方法

当用户对某些广播感兴趣的话,此时能够获取此广播,而后在onReceive方法中处理接收广播的一下操做。

public class CustomBroadcast extends BroadcastReceiver {
    public CustomBroadcast() {
    }

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

        if (intent.getAction().equals("SendCustomBroadcast")){
            Toast.makeText(context,"自定义广播接收成功:Action:SendCustomBroadcast",Toast.LENGTH_SHORT).show();
        }
    }
}
注意自定义广播是在 Androidmanfest.xml 中静态注册的。

2.发送有序广播

广播在Android是有优先级的,优先级高的广播能够终止或修改广播内容。发送有序广播的方法以下sendOrderedBroadcast(intent,"str_receiver_permission");

例如:发送自定义有序广播

Intent customOrderIntent=new Intent();
        customOrderIntent.setAction("SendCustomOrderBroadcast");
        customOrderIntent.putExtra("str_order_broadcast","老板说:公司每人发 10 个 月饼");
        sendOrderedBroadcast(customOrderIntent,"android.permission.ORDERBROADCAST");

广播属于四大组件,必定要在AndroidMainfest.xml 中注册。

有序广播静态注册

接收有序广播的静态注册方法以下:

<receiver
            android:name=".component.BroadcastReceiver.CustomHightBrodcast"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter android:priority="1000">
                <action android:name="SendCustomOrderBroadcast" />
            </intent-filter>
        </receiver>

        <receiver
            android:name=".component.BroadcastReceiver.CustomMiddleBroadcast"
            android:enabled="true"
            android:exported="true"
          >
            <intent-filter android:priority="500">
                <action android:name="SendCustomOrderBroadcast" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".component.BroadcastReceiver.CustomLowerBroadcast"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter android:priority="100">
                <action android:name="SendCustomOrderBroadcast" />
            </intent-filter>
        </receiver>
    1. 有序广播,高优先级广播能够优先处理
public class CustomHightBrodcast extends BroadcastReceiver {
    public CustomHightBrodcast() {
    }

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

        if (intent.getAction().equals("SendCustomOrderBroadcast")) {
            Toast.makeText(context, intent.getStringExtra("str_order_broadcast"), Toast.LENGTH_SHORT).show();
            Bundle bundle=new Bundle();
            bundle.putString("str_order_broadcast","经理说:公司每人发 5 个 月饼");
//            修改广播传输数据
            setResultExtras(bundle);
        }
    }
}
    1. 中优先级的广播后序处理
public class CustomMiddleBroadcast extends BroadcastReceiver {
    public CustomMiddleBroadcast() {
    }
    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals("SendCustomOrderBroadcast")) {
            Toast.makeText(context, getResultExtras(true).getString("str_order_broadcast"), Toast.LENGTH_SHORT).show();
            Bundle bundle=new Bundle();
            bundle.putString("str_order_broadcast","主管说:公司每人发 2 个 月饼");
            setResultExtras(bundle);
        }
    }
}
    1. 低优先级广播最后处理
public class CustomLowerBroadcast extends BroadcastReceiver {
    public CustomLowerBroadcast() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("SendCustomOrderBroadcast")) {
            String notice= getResultExtras(true).getString("str_order_broadcast");
            Toast.makeText(context,notice, Toast.LENGTH_SHORT).show();
//          终止广播继续传播下去
            abortBroadcast();
        }
    }
}

注意 :
有序广播须要声明并使用权限

  • 1.声明使用权限
<!-- 申请使用自定义 有序广播的权限 -->
 <uses-permission >   android:name="android.permission.ORDERBROADCAST" />
  • 2.声明权限
<!-- 自定义 有序广播的权限 -->
 <permission>
android:name="android.permission.ORDERBROADCAST"/>

在有序广播中高优先级的广播接收广播,能够修改数据,而后传给低优先级的广播。

3.发送持续广播(已经被弃用)

粘性广播会在Android 系统中一直存在,不过随着 Android系统的不断更新,此方法逐渐被抛弃,使用方法以下:sendStickyBroadcast(intent);

5.广播接收(系统广播、自定义广播)

当广播发出后,如何接收广播呢,下面将介绍接收广播的方法。
接受广播类 主要继承 BroadcastReceiver,而后在onReceive方法,过滤广播Action中携带的Intent,而后进行相关处理。

接收开机广播的方法

1. 实现BootReceiverMethod 继承 BroadcastReceiver

p ublic class BootReceiverMethod extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //   接收开机广播处理事情,好比启动服务
        Intent mStartIntent = new Intent(context, StartServiceMethods.class);
        context.startService(mStartIntent);
    }
}

2.在Androidmainfest.xml 声明组件信息,并过滤开机完成 Action

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

3.声明接收开机广播完成的权限

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

极力推荐文章:欢迎收藏
Android 干货分享

阅读五分钟,每日十点,和您一块儿终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,经过阅读本篇文章,您将收获如下内容:

  1. Service 简介
  2. 四大组件之一,必须在Androidmainfest.xml 中注册
  3. 启动模式启动服务
  4. 绑定模式绑定服务
  5. 前台服务
  6. AIDL远程服务

Service Android 四大组件之一(Activity 活动,Service 服务,ContentProvider 内容提供者,BroadcastReceiver 广播),与Activity相比,Activity 是运行在前台,用户能够看得见,Service 则是运行在后台,无用户界面,用户没法看到。

Service主要用于组件之间交互(例如:与ActivityContentProviderBroadcastReceiver进行交互)、后台执行耗时操做等(例以下载文件,播放音乐等,但Service在主线程运行时长不能超过20s,不然会出现ANR,耗时操做通常建议在子线程中进行操做)。

1.Service 简介

在了解Service 的生命周期的以前,咱们先了解一下Service 的继承关系,方便咱们更好的了解Service

Service 继承关系以下:

java.lang.Object
   ↳    android.content.Context
        ↳    android.content.ContextWrapper
             ↳    android.app.Service

Service 的两种启动模式

Service 有两种不一样的启动模式 ,不一样的启动模式对应不一样生命周期.
Service 启动模式主要分两种: 1. 启动模式。 2. 绑定模式。

1.启动模式

此模式经过 startService()方法启动,此服务能够在后台一直运行,不会随启动组件的消亡而消亡。只能执行单一操做,没法返回结果给调用方,经常使用于网络下载、上传文件,播放音乐等。

2.绑定模式

此模式 经过绑定组件(Activity等)调用 bindService() 启动,此服务随绑定组件的消亡而解除绑定。

若是此时没有其它经过startService()启动,则此服务会随绑定组件的消亡而消亡。
多个组件不只能够同时绑定一个Service,并且能够经过进程间通讯(IPC)执行跨进程操做等。

3.两种服务能够同时运行

启动模式与绑定模式的服务能够同时运行,在销毁服务时,只有两种模式都不在使用Service时候,才能够销毁服务,不然会引发异常。

4. 两种 Service 模式的生命周期

两种 Service 模式的生命周期以下:

两种 Service 模式生命周期图

2.四大组件之一,必须在Androidmainfest.xml 中注册

Service 注册方法以下:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ServiceMethods" />
      ...
  </application>
</manifest>

注意:

Service 如不注册 ,不会像Activity 那样会致使App CrashService 不注册 不会报异常信息,可是服务会起不来,如不注意很容易迷惑。

3.启动模式

经过启动模式启动的Service ,如不主动关闭,Service会一直在。

启动模式启动服务的方法

Intent  mBindIntent = new Intent(ServiceMethods.this, BindServiceMethods.class);
        startService(mStartIntent);

启动模式启动服务的生命周期

下面是验证启动模式启动服务的生命周期的方法,详细生命周期请查看上方Service的生命周期图。

01-03 17:16:36.147 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onCreate----
01-03 17:16:36.223 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onStartCommand----
01-03 17:16:38.174 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onDestroy----

启动模式 启动服务案例

此案例功能:启动服务,在服务中建立通知

// Service 建立方法
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "----onCreate----");
    }
    // Service  启动方法
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "----onStartCommand----");
        // 获取NotificationManager实例
        notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        // 实例化NotificationCompat.Builder并设置相关属性
        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                this)
        // 设置小图标
                .setSmallIcon(R.drawable.ic_launcher)
                .setLargeIcon(
                        BitmapFactory.decodeResource(getResources(),
                                R.drawable.ic_launcher))
                // 设置通知标题
                .setContentTitle("我是经过StartService服务启动的通知")
                // 设置通知不能自动取消
                .setAutoCancel(false).setOngoing(true)
                // 设置通知时间,默认为系统发出通知的时间,一般不用设置
                // .setWhen(System.currentTimeMillis())
                // 设置通知内容
                .setContentText("请使用StopService 方法中止服务");

        // 经过builder.build()方法生成Notification对象,并发送通知,id=1
        notifyManager.notify(1, builder.build());

        return super.onStartCommand(intent, flags, startId);
    }
    // Service  销毁方法
    @Override
    public void onDestroy() {
        Log.i(TAG, "----onDestroy----");
        notifyManager.cancelAll();
        super.onDestroy();
    }

4. 绑定模式启动绑定服务

绑定模式启动的服务会随着绑定逐渐的消亡而解除Service绑定,若是此时Service没有经过启动模式启动,则此服务将会被销毁。

绑定模式启动绑定服务的方法

绑定模式,是经过其余组件启动的Service

启动绑定模式服务的方法

// 启动绑定服务处理方法
    public void BtnStartBindService(View view) {
        // 启动绑定服务处理方法
        bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        isBindService = true;
        Toast.makeText(ServiceMethod.this, "启动 " + mBindCount + " 次绑定服务",
                Toast.LENGTH_SHORT).show();
    }

    
    public void BtnSopBindService(View view) {
        if (isBindService) {
            // 解除绑定服务处理方法
            unbindService(serviceConnection);
            Toast.makeText(ServiceMethod.this, "解除 " + mUnBindCount + " 次绑定服务",
                    Toast.LENGTH_SHORT).show();
            isBindService = false;
        }

    }

绑定服务 随绑定组件的消亡而消亡

绑定模式 生命周期回调代码以下:

// Service 建立方法
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "----onCreate----");
    }

    // Service 绑定方法
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "----onBind----");

        MyBinder myBinder = new MyBinder();
        return myBinder;
    }

    // Service 解除绑定方法
    @Override
    public boolean onUnbind(Intent intent) {

        Log.i(TAG, "----onUnbind----");
        return super.onUnbind(intent);

    }

    // Service 销毁方法
    @Override
    public void onDestroy() {
        Log.i(TAG, "----onDestroy----");
        super.onDestroy();
    }

绑定服务的生命周期代码打印Log信息以下:

01-03 20:32:59.422 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onCreate----
01-03 20:32:59.423 13306-13306/com.android.program.programandroid I/BindService wjwj:: -----onBind-----
01-03 20:33:09.265 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onUnbind----
01-03 20:33:09.266 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onDestroy----

绑定服务案例

功能:获取绑定模式启动 绑定服务及解除绑定服务的次数

绑定服务类

package com.android.program.programandroid.component.Service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class BindServiceMethods extends Service {
    private static final String TAG = "BindService wjwj:";

    public BindServiceMethods() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "----onCreate----");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "----onBind----");

        MyBinder myBinder = new MyBinder();
        return myBinder;
    }


    @Override
    public boolean onUnbind(Intent intent) {

        Log.i(TAG, "----onUnbind----");
        return super.onUnbind(intent);

    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "----onDestroy----");
        super.onDestroy();
    }
}
  • 组件与绑定服务类之间的交互
//    启动绑定服务处理方法
    public void BtnStartBindService(View view) {

        bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        isBindService = true;
        Toast.makeText(ServiceMethods.this,"启动 "+mBindCount+" 次绑定服务",Toast.LENGTH_SHORT).show();
    }

    //    解除绑定服务处理方法
    public void BtnSopBindService(View view) {
        if (isBindService) {
            unbindService(serviceConnection);
            Toast.makeText(ServiceMethods.this,"解除 "+mUnBindCount+" 次绑定服务",Toast.LENGTH_SHORT).show();
            isBindService=false;
        }

    }
  • 组件之间交互所需的 Binder 接口类
/**
* 该类提供 绑定组件与绑定服务提供接口
* */
public class MyBinder extends Binder {
   private int count = 0;

    public int getBindCount() {
        return ++count;
    }
    public int getUnBindCount() {
        return count> 0 ? count-- : 0;
    }
}

5. 提升服务的优先级

服务默认启动方式是后台服务,可是能够经过设置服务为前台服务,提升服务的优先级,进而避免手机内存紧张时,服务进程被杀掉。

设置前台服务的两种方法

1.设置为前台服务

//设置为前台服务
startForeground(int, Notification)

2.取消前台服务

//取消为前台服务
stopForeground(true);

startForeground 前台服务案例

功能:前台服务绑定通知信息,提升服务进程优先级,不然取消通知信息

package com.android.program.programandroid.component.Service;

import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;

import com.android.program.programandroid.R;

public class MyStartForcegroundService extends Service {

    public MyStartForcegroundService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent.getAction().equals("start_forceground_service")) {

//        获取NotificationManager实例
            NotificationManager notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//        实例化NotificationCompat.Builder并设置相关属性
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
//                设置小图标
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
//                设置通知标题
                    .setContentTitle("我是经过startForeground 启动前台服务通知")
//                设置通知不能自动取消
                    .setAutoCancel(false)
                    .setOngoing(true)
//                设置通知时间,默认为系统发出通知的时间,一般不用设置
//                .setWhen(System.currentTimeMillis())
//               设置通知内容
                    .setContentText("请使用stopForeground 方法改成后台服务");

            //经过builder.build()方法生成Notification对象,并发送通知,id=1
//        设置为前台服务
            startForeground(1, builder.build());

        } else if (intent.getAction().equals("stop_forceground_service")) {
            
            stopForeground(true);
        }

        return super.onStartCommand(intent, flags, startId);
    }
}

6. 使用AIDL接口实现远程绑定

因为内容较多,后续另开一篇详细介绍。

至此,本篇已结束,若有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

微信关注公众号:  程序员Android,领福利

相关文章
相关标签/搜索