android 给广播发送消息_android service给静态广播发送消息 - CSDN
  • Android发送广播Broadcast

    2016-09-06 10:52:11
    BroadcastReceiver本质上时一种全局的监听器,用于监听系统全局的广播消息,实现系统中不同组件之间的通信。  调用sendBroadcast()即可发送广播,这条广播会启动intent参数所对应的BroadcastReceiver。使用...

        BroadcastReceiver本质上时一种全局的监听器,用于监听系统全局的广播消息,实现系统中不同组件之间的通信。

        调用sendBroadcast()即可发送广播,这条广播会启动intent参数所对应的BroadcastReceiver。使用BroadcastReceiver来接受广播。


        下面是一个简单的实例

        工程结构:


        

        AndroidManifest.xml

    <span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.leidong.broadcast">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <receiver android:name=".MyService">
                <intent-filter >
                    <action android:name="com.example.leidong.action.MyReceiver"/>
                </intent-filter>
            </receiver>
        </application>
    
    </manifest></span>


    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#2b2b2b">
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5pt"
            android:layout_marginRight="5pt"
            android:layout_marginTop="20pt"
            android:text="S E N D"
            android:textColor="#ffffff"
            android:textStyle="bold"
            android:id="@+id/send"
            android:background="#696969"
            android:layout_gravity="center_horizontal" />
    </LinearLayout>
    


    MainActivity.java

    package com.example.leidong.broadcast;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
        Button send;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            //获取程序界面中的按钮
            send = (Button)findViewById(R.id.send);
            send.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //创建Intent
                    Intent intent = new Intent();
                    intent.setAction("com.example.leidong.action.MyReceiver");
                    intent.putExtra("msg", "简单的消息");
                    //发送广播
                    sendBroadcast(intent);
                }
            });
        }
    }
    


    MyReceiver.java

    package com.example.leidong.broadcast;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.widget.Toast;
    
    /**
     * Created by Lei Dong on 2016/09/05.
     */
    public class MyReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,
                    "接收到的Intent的Action为:" + intent.getAction() + "\n 消息内容是:" + intent.getStringExtra("msg"),
                    Toast.LENGTH_LONG).show();
        }
    }
    

    AVD运行效果:




    展开全文
  • 基于Android 7.0源码,分析Android广播机制的发送过程。 按照广播的类型,可以分为普通广播、有序广播和sticky广播。

    基于Android 7.0源码,分析Android广播机制的发送过程。

    一、概述

      按照广播的类型,可以分为普通广播、有序广播和sticky广播。在注册广播的时候,可以设置优先级,在发送order广播的时候,广播注册者根据优先级顺序依次接受intent,但是发送普通广播的时候,会忽略广播接收者的优先级,并将广播发送给所有符合条件的广播接收者处理。
    - 普通广播:
      所有匹配的接收器都会接收到此广播;
    - 有序广播:
      根据广播接收器的IntentFilter的priority属性值的大小一次调用,并可以通过调用abortBroadcast()阻止广播继续向下传播;
    - sticky广播:
      可以在接收器注册之前发出的广播,sticky广播在发送后就一直存在于系统的消息容器里面,等待对应的接收器去处理,如果暂时没有接收器处理这个消息则一直在消息容器里面处于等待状态。

      从ContextImpl.java文件中,Android 7.0提供了如下发送广播的接口:
    - public void sendBroadcast(Intent intent)
    - public void sendBroadcast(Intent intent, int userId)
    - public void sendBroadcast(Intent intent, String receiverPermission)
    - public void sendOrderedBroadcast(Intent intent, String receiverPermission)
    - public void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
    - public void sendStickyBroadcast(Intent intent)
    - public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

      sendBroadcast是最简单发送广播的接口。
      sendOrderedBroadcast是用来向系统发出有序广播,有序广播对应的所有接收器只能按照一定的优先级顺序依次接收intent,优先级可以记录在AndroidManifest.xml文件中的元素的android:priority属性中,其数值越大表示优先级越高,取值范围为-1000到1000;也可以调用IntentFilter对象的setPriority()方法来设置优先级。
      对于有序广播而言,前面的接收者可以对接收到的广播intent进行处理,并将处理结果放置到广播intent中,然后传递给下一个接收者,并且前面的接收者有权调用BroadcastReceiver.abortBroadcast终止该广播的进一步继续传播。
      粘性广播可以保证在广播发送时尚未注册的receiver,一旦后面注册时,就能够马上接到之前发送过的sticky广播。

      下面就来说说具体广播发送的流程。

    二、广播发送流程

      我们以在activity中发送最简单的普通广播为例,在发送方,一般会类似如下代码来发送广播:

    Intent intent = new Intent();
    intent.setAction("com.android.xxxxx");
    //intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);//前台广播(默认是后台广播)
    sendBroadcast(intent);

      在activity中直接调用sendBroadcast,实际调用的是ContextImpl.java中的同名同参的sendBroadcast接口。

    1. ContextImpl.sendBroadcast

    [===>frameworks\base\core\java\android\app\ContextImpl.java]

    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
            ActivityManagerNative.getDefault().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }

      这样就直接调用到了ActivityManagerService端broadcastIntent那去了。

    2. ActivityManagerService.broadcastIntent

    [===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]

    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle options,
            boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);
    
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, null, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

      直接来看broadcastIntentLocked,该函数的代码比较长,按照具体功能来说,具体的处理大概有以下几点:
    - 1、给intent默认添加FLAG_EXCLUDE_STOPPED_PACKAGES标记;
    - 2、处理与package等其他系统广播,判断是否有权限发送广播;
    - 3、若发送的是粘性广播,需要更新系统的粘性广播列表;
    - 4、获取与intent匹配的静态receiver列表receivers;
    - 5、获取与intent匹配的动态receiver列表registeredReceivers;
    - 6、向并行receiver发送广播;
    - 7、将剩下的并行receiver按照优先级合并到静态receiver列表receivers中,此时作为串行receiver列表;
    - 8、依次向串行receivers发送广播;

    3. ActivityManagerService.broadcastIntentLocked

    [===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]

    3.1 给intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记

    // By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

      在3.1之后,系统的PakcageManagerService增加了对处于“stopped state”应用的管理,这个stopped和Activity生命周期中的stop状态是完全两码事,指的是安装后从来没有启动过或者被用户手动强制停止的应用。
      注意到系统增加了2个Flag:FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES ,来标识一个intent是否激活处于“stopped state”的应用。

    /**
     * If set, this intent will not match any components in packages that
     * are currently stopped.  If this is not set, then the default behavior
     * is to include such applications in the result.
     */
    public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010;
    
    /**
     * If set, this intent will always match any components in packages that
     * are currently stopped.  This is the default behavior when
     * {@link #FLAG_EXCLUDE_STOPPED_PACKAGES} is not set.  If both of these
     * flags are set, this one wins (it allows overriding of exclude for
     * places where the framework may automatically set the exclude flag).
     */
    public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;

      从上面注释可以知道,如果intent同时设置了FLAG_EXCLUDE_STOPPED_PACKAGES和FLAG_INCLUDE_STOPPED_PACKAGES标记的话,它会覆盖掉FLAG_EXCLUDE_STOPPED_PACKAGES标记。具体的代码,介绍后面获取与intent匹配的receiver列表会贴出代码。
      注意,FLAG_INCLUDE_STOPPED_PACKAGES标记只对开发者自定义的广播有效,对于系统广播是无效的。

    3.2 处理与package等其他系统广播,判断是否有权限发送广播

      这部分代码略过去了。

    3.3 若发送的是粘性广播,需要更新系统的粘性广播列表

    if (sticky) {
        if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                callingPid, callingUid)
                != PackageManager.PERMISSION_GRANTED) {//检查是否申请了发送粘性广播权限BROADCAST_STICKY
            ...
        }
    
        if (userId != UserHandle.USER_ALL) {
            ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
                    UserHandle.USER_ALL);
            if (stickies != null) {
                ArrayList<Intent> list = stickies.get(intent.getAction());
                if (list != null) {
                    int N = list.size();
                    int i;
                    for (i=0; i<N; i++) {
                        if (intent.filterEquals(list.get(i))) {
                            ...
                        }
                    }
                }
            }
        }
        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
        if (stickies == null) {
            stickies = new ArrayMap<>();
            mStickyBroadcasts.put(userId, stickies);
        }
        ArrayList<Intent> list = stickies.get(intent.getAction());
        if (list == null) {
            list = new ArrayList<>();
            stickies.put(intent.getAction(), list);
        }
        final int stickiesCount = list.size();
        int i;
        for (i = 0; i < stickiesCount; i++) {
            if (intent.filterEquals(list.get(i))) {//比较
                // This sticky already exists, replace it.
                list.set(i, new Intent(intent));
                break;
            }
        }
        if (i >= stickiesCount) {
            list.add(new Intent(intent));
        }
    }

      如果发送方调用的是sendStickyBroadcast时,此处的sticky变量为true。此时要记录发送的intent,就会更新mStickyBroadcasts表。mStickyBroadcasts的定义如下:

    /**
     * State of all active sticky broadcasts per user.  Keys are the action of the
     * sticky Intent, values are an ArrayList of all broadcasted intents with
     * that action (which should usually be one).  The SparseArray is keyed
     * by the user ID the sticky is for, and can include UserHandle.USER_ALL
     * for stickies that are sent to all users.
     */
    final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
            new SparseArray<ArrayMap<String, ArrayList<Intent>>>();

      上面代码判断mStickyBroadcasts中是否存在相同的粘性广播,判断的过程是由Intent.filterEquals来执行,只会判断intent的action、data、type、package、component和categories信息。如果两个intent的data是不一样的,那么就会在ArrayList中为正在发送的粘性广播新增一项;如果两个intent的action、data、type、package、component和categories信息都相同,就会用新的(正在发送的)粘性广播intent替换掉旧的。

      从上篇文章《Android广播机制——广播的注册》的动态注册小节中知道,每次动态注册receiver时,都会遍历一下mStickyBroadcast表,查看哪些intent可以和新receiver的intentfilter匹配,只有匹配的intent才会递送给新注册的动态receiver。
      这里在用张图来说明动态注册时有关粘性广播的处理。
    新建 Microsoft Office Visio 绘图 (2).png
      相亲对象——新注册的动态receiver的filter对action1和action4感兴趣,遍历时只会考虑action1和action4对应的子表ArrayList,并且两个子表可能只有一部分符合filter的择偶要求,最后才能和receiver相亲成功。
      粘性广播和普通广播的发送过程除了更新mStickyBroadcasts表的动作外,没有什么其他的代码差异了。
      继续接着看。

    3.4 获取与intent匹配的静态receiver列表receivers

    List receivers = null;
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
             == 0) {
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }
    private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
            int callingUid, int[] users) {
        List<ResolveInfo> receivers = null;
        try {
            HashSet<ComponentName> singleUserReceivers = null;
            boolean scannedFirstReceivers = false;
            for (int user : users) {
    
                List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                        .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
    
    
                if (receivers == null) {
                    receivers = newReceivers;
                } else if (newReceivers != null) {
    
                }
            }
        } catch (RemoteException ex) {
            // pm is in same process, this will never happen.
        }
        return receivers;
    }

      使用包管理器的queryIntentReceivers()接口,查询出和intent匹配的所有静态receivers,此时所返回的查询结果本身已经排好序了,该返回值被直接赋值给了receivers变量。

    3.5 获取与intent匹配的动态receiver列表registeredReceivers

    registeredReceivers = mReceiverResolver.queryIntent(intent,
            resolvedType, false, userId);

      从上篇文章《Android广播机制——广播的注册》的动态注册小节中知道,每次动态注册receiver时,都会创建对应BroadcastFilter,并将将注册的BroadcastFilter加入到mReceiverResolver中。
      因此,这里只要直接通过intent就可以获取到对intent感兴趣的动态receiver列表registeredReceivers。
      这里提一下,在获取动态注册receiver列表的过程中,会调用Intent.isExcludingStopped接口对intent是否被设置了FLAG_EXCLUDE_STOPPED_PACKAGES或者FLAG_INCLUDE_STOPPED_PACKAGES标记进行判断,依据下面代码可知,FLAG_INCLUDE_STOPPED_PACKAGES标记确实是可以覆盖FLAG_EXCLUDE_STOPPED_PACKAGES标记的。

    mReceiverResolver.queryIntent(intent, resolvedType, false, userId)
        buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, firstTypeCut, finalList, userId);
            intent.isExcludingStopped()
    
    
    public class Intent implements Parcelable, Cloneable {
            ...
            public boolean isExcludingStopped() {
                return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES))
                        == FLAG_EXCLUDE_STOPPED_PACKAGES;
            }
            ...
    }

    3.6 向并行receiver发送广播

    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    if (!ordered && NR > 0) {
        // If we are not serializing this broadcast, then send the
        // registered receivers separately so they don't wait for the
        // components to be launched.
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
                resultExtras, ordered, sticky, false, userId);
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
        final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
        if (!replaced) {
            queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
        registeredReceivers = null;
        NR = 0;
    }

      registeredReceivers列表存放的是动态注册的receiver,如果目前发送的是无序广播,那就会以并行的形式发送,并且将此时的registeredReceivers清空;如果目前发送的是有序广播,那就会以串行的形式发送,registeredReceivers列表就会放在下一步中合并到receivers列表后作为串行列表。
      首先将依据intent新创建的BroadcastRecord节点入列BroadcastQueue的mParallelBroadcasts中,然后进行并行广播发送。并行广播的发送时,是发送完上一个,紧接着就发下一个,不会做任何的等待操作。至于发送的过程放到后面串行广播发送时再说。
      Android系统关于广播有两个广播队列——前台广播队列mFgBroadcastQueue和后台广播队列mBgBroadcastQueue。在发送方发送广播时,默认是放置在后台广播队列的。但是发送方在给intent设置FLAG_RECEIVER_FOREGROUND标记后,发送的广播就会被放置在前台广播队列。

    3.7 将剩下的并行receiver按照优先级合并到静态receiver列表receivers中,此时作为串行receiver列表

      这里代码挺简单的就不贴出来了,只要知道会过滤一些特定的系统广播,并且会按照receiver的优先级来排序,合并到串行receivers列表中。

    3.8 依次向串行receivers发送广播

    if ((receivers != null && receivers.size() > 0)
            || resultTo != null) {
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType,
                requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId);
    
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                + ": prev had " + queue.mOrderedBroadcasts.size());
        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                "Enqueueing broadcast " + r.intent.getAction());
    
        boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
        if (!replaced) {
            queue.enqueueOrderedBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
    } else {
        // There was nobody interested in the broadcast, but we still want to record
        // that it happened.
        if (intent.getComponent() == null && intent.getPackage() == null
                && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            // This was an implicit broadcast... let's record it for posterity.
            addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
        }
    }

      和3.6小节类似,首先将依据intent新创建的BroadcastRecord节点入列BroadcastQueue的mOrderedBroadcasts中,然后进行串行广播发送。

      串行广播和并行广播发送时都是使用的BroadcastQueue.scheduleBroadcastsLocked,最终会间接的使用BroadcastQueue.processNextBroadcast(),由于这段过程比较复杂,单独拿出来做一节的分析。

    4. BroadcastQueue.processNextBroadcast

    [===>frameworks\base\services\core\java\com\android\server\am\BroadcastQueue.java]
      流程比较长,根据具体的处理,大致可以分成四个部分:
    - 1、发送并行广播;
    - 2、发送当前有序广播;
    - 3、获取并发送下一条有序广播;

    4.1 发送并行广播

    while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();
        final int N = r.receivers.size();
    
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);
    
            deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
        }
        addBroadcastToHistoryLocked(r);
    
    }

      在之前第3.6小节,向并行receiver发送广播前会依据动态注册的receiver列表registeredReceivers和intent来创建BroadcastRecord节点,这样BroadcastRecord.receivers存储着对intent感兴趣的receiver列表。然后在这里发送前一个个遍历发送。

    4.1.1 BroadcastQueue.deliverToRegisteredReceiverLocked

    try {
    
        if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
            // Skip delivery if full backup in progress
            // If it's an ordered broadcast, we need to continue to the next receiver.
            if (ordered) {
                skipReceiverLocked(r);
            }
        } else {
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
        }
    
    } catch (RemoteException e) {
        ...
    }

    4.1.2 BroadcastQueue.performReceiveLocked

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        // Send the intent to the receiver asynchronously using one-way binder calls.
        if (app != null) {
            if (app.thread != null) {
                // If we have an app thread, do the call through that so it is
                // correctly ordered with other one-way calls.
                try {
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
    
                } catch (RemoteException ex) {
                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
    
                }
            } else {
                // Application has died. Receiver doesn't exist.
    
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

      随后就转到了ActivityThread中去了。注意,这里的receiver对应的是
    ReceiverDispatcher的Binder实体——InnerReceiver了。

    4.1.3 ActivityThread.scheduleRegisteredReceiver

    // This function exists to make sure all receiver dispatching is
    // correctly ordered, since these are one-way calls and the binder driver
    // applies transaction ordering per object for such calls.
    public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String dataStr, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException {
        updateProcessState(processState, false);
        receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
    }

    4.1.3 InnerReceiver.performReceive

    4.1.4 ReceiverDispatcher.performReceive

    [===>frameworks\base\core\java\android\app\LoadedApk.java]

    static final class ReceiverDispatcher {
    
        ...
        final Handler mActivityThread;
        ...
        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
            Handler activityThread, Instrumentation instrumentation,
            boolean registered) {
            ...
            mActivityThread = activityThread;
            ...
        }
    
        final static class InnerReceiver extends IIntentReceiver.Stub {
            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
    
                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);//调用ReceiverDispatcher.performReceive
                } else {
                    ...
                }
            }
        }
    
        ...
    
        public void performReceive(Intent intent, int resultCode, String data,
            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
    
            if (intent == null || !mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
    
                    args.sendFinished(mgr);
                }
            }
        }
    
    }

      在ReceiverDispatcher.performReceive中有创建Args对象,并且有调用mActivityThread.post(args),mActivityThread是之前注册广播接收器时指定的,若用户注册时未指定handler,则此时的mActivityThread就为应用进程的主线程,这里将新创建的Args给post到了mActivityThread这个Handler中,把消息放入MessageQueue,再调用Args的run()方法。

    4.1.5 LoadedApk.Args.run

    [===>frameworks\base\core\java\android\app\LoadedApk.java]

    static final class ReceiverDispatcher {
        ...
    
        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
            ...
    
            public void run() {
                final BroadcastReceiver receiver = mReceiver;
    
                ...
    
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
                try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();//获取mReceiver的类加载器
                    intent.setExtrasClassLoader(cl);
                    intent.prepareToEnterProcess();
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);//回调具体receiver的onReceive方法
                } catch (Exception e) {
                    ...
                }
    
                if (receiver.getPendingResult() != null) {
                    finish();
                }
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
    
        ...
    }

      终于看到了很熟悉的onReceive函数,这里利用反射机制,创建出BroadcastRecord对象,随后回调该对象的onReceive。
      这里最后调用了finish,由于Args继承BroadcastReceiver.PendingResult,PendingResult有finish,所以这里实际上调用的是BroadcastReceiver.PendingResult.finish。

    4.1.6 BroadcastReceiver.PendingResult.finish

    [===>frameworks\base\core\java\android\content\BroadcastReceiver.java]

    public abstract class BroadcastReceiver {
        private PendingResult mPendingResult;
    
        public static class PendingResult {
            public final void finish() {
                if (mType == TYPE_COMPONENT) {
                    final IActivityManager mgr = ActivityManagerNative.getDefault();
                    if (QueuedWork.hasPendingWork()) {
    
                        QueuedWork.singleThreadExecutor().execute( new Runnable() {
                            @Override public void run() {
    
                                sendFinished(mgr);
                            }
                        });
                    } else {
    
                        sendFinished(mgr);
                    }
                } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
    
                    final IActivityManager mgr = ActivityManagerNative.getDefault();
                    sendFinished(mgr);
                }
            }
    
            ...
        }
    
        public void sendFinished(IActivityManager am) {
            synchronized (this) {
                if (mFinished) {
                    throw new IllegalStateException("Broadcast already finished");
                }
                mFinished = true;
    
                try {
                    if (mResultExtras != null) {
                        mResultExtras.setAllowFds(false);
                    }
                    if (mOrderedHint) {
                        am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                                mAbortBroadcast, mFlags);
                    } else {
    
                        am.finishReceiver(mToken, 0, null, null, false, mFlags);
                    }
                } catch (RemoteException ex) {
                }
            }
        }
    
        ...
    }

      上面无论如何都会最终调用到ActivityManagerService.finishReceiver。

    4.1.7 ActivityManagerService.finishReceiver

    [===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]

    public void finishReceiver(IBinder who, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {
        ...
    
        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doNext = false;
            BroadcastRecord r;
    
            synchronized(this) {
                BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                        ? mFgBroadcastQueue : mBgBroadcastQueue;
                r = queue.getMatchingOrderedReceiver(who);
                if (r != null) {
                    doNext = r.queue.finishReceiverLocked(r, resultCode,
                        resultData, resultExtras, resultAbort, true);
                }
            }
    
            if (doNext) {
                r.queue.processNextBroadcast(false);
            }
            trimApplications();
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

    4.2 发送当前有序广播

    if (mPendingBroadcast != null) {
    
        boolean isDead;
        synchronized (mService.mPidsSelfLocked) {
            ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);//从mPidsSelfLocked获取正在处理该广播进程
            isDead = proc == null || proc.crashing;//判断该进程是否死亡
        }
        if (!isDead) {
            // It's still alive, so keep waiting
            return;
        } else {
    
            mPendingBroadcast.state = BroadcastRecord.IDLE;
            mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
            mPendingBroadcast = null;
        }
    }
    
    boolean looped = false;
    
    do {
        if (mOrderedBroadcasts.size() == 0) {
            // No more broadcasts pending, so all done!
            mService.scheduleAppGcsLocked();//所有串行广播处理完成,则调度执行gc
            if (looped) {
                // If we had finished the last ordered broadcast, then
                // make sure all processes have correct oom and sched
                // adjustments.
                mService.updateOomAdjLocked();
            }
            return;
        }
        r = mOrderedBroadcasts.get(0);//获取第一条串行广播
        boolean forceReceive = false;
    
        // Ensure that even if something goes awry with the timeout
        // detection, we catch "hung" broadcasts here, discard them,
        // and continue to make progress.
        //
        // This is only done if the system is ready so that PRE_BOOT_COMPLETED
        // receivers don't get executed with timeouts. They're intended for
        // one time heavy lifting after system upgrades and can take
        // significant amounts of time.
        int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;//获取所接收该广播的接受者receiver个数
        if (mService.mProcessesReady && r.dispatchTime > 0) {
            long now = SystemClock.uptimeMillis();
            if ((numReceivers > 0) &&
                    (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {//广播处理超时,预定的超时时间为2*mTimeoutPeriod*numReceivers
    
                broadcastTimeoutLocked(false); // forcibly finish this broadcast
                forceReceive = true;
                r.state = BroadcastRecord.IDLE;
            }
        }
    
        if (r.state != BroadcastRecord.IDLE) {
    
            return;
        }
    
        if (r.receivers == null || r.nextReceiver >= numReceivers
                || r.resultAbort || forceReceive) {//无receiver接收;已发送给所有receiver;其中一个receiver调用了abortBroadcast;在时限内未发送给所有receiver
            // No more receivers for this broadcast!  Send the final
            // result if requested...
            if (r.resultTo != null) {
                try {
    
                    performReceiveLocked(r.callerApp, r.resultTo,
                        new Intent(r.intent), r.resultCode,
                        r.resultData, r.resultExtras, false, false, r.userId);//处理广播,将会调用到BroadcastReceiver.onReceive
                    // Set this to null so that the reference
                    // (local and remote) isn't kept in the mBroadcastHistory.
                    r.resultTo = null;
                } catch (RemoteException e) {
                    r.resultTo = null;
    
                }
            }
    
            cancelBroadcastTimeoutLocked();//移除BROADCAST_TIMEOUT_MSG消息
    
            // ... and on to the next...
            addBroadcastToHistoryLocked(r);
            if (r.intent.getComponent() == null && r.intent.getPackage() == null
                    && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                // This was an implicit broadcast... let's record it for posterity.
                mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                        r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
            }
            mOrderedBroadcasts.remove(0);//移除掉该BroadcastRecord节点(移除动作只有这一处)
            r = null;
            looped = true;
            continue;
        }
    } while (r == null);

      在处理有序广播时,就要涉及到广播超时的问题了。
      我们知道,系统中前台广播队列和后台广播队列。它们的时限要求有所不同。我们从代码中就可以知道,对于一个BroadcastRecord的超时时间是多少。

    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
    if (mService.mProcessesReady && r.dispatchTime > 0) {
        long now = SystemClock.uptimeMillis();
        if ((numReceivers > 0) &&
                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
    
            broadcastTimeoutLocked(false); // forcibly finish this broadcast
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }

      对于前台广播队列,其mTimeoutPeriod为BROADCAST_FG_TIMEOUT = 10*1000ms = 10秒;对于后台广播队列,其mTimeoutPeriod为BROADCAST_BG_TIMEOUT = 60*1000ms = 60秒。
      根据上面对于超时时限的计算。举个例子,如果“前台广播队列”的某个BroadcastRecord节点对应了3个receiver,那么在处理这个广播节点时,只要能在2x10x3=60秒内搞定就可以了,超过这个时限就会被认为发送该广播超时。
      对于并行receiver而言,时限的作用小一点儿,因为动态receiver是直接递送到目标进程的,它不考虑目标端是什么时候处理完这个广播的。

    4.3 获取并发送下一条有序广播

    // Get the next receiver...
    int recIdx = r.nextReceiver++;//获取下一receiver的index索引值
    
    // Keep track of when this receiver started, and make sure there
    // is a timeout message pending to kill it if need be.
    r.receiverTime = SystemClock.uptimeMillis();
    if (recIdx == 0) {//处理对有序广播感兴趣的第一个receiver
        r.dispatchTime = r.receiverTime;//此时开始计时
        r.dispatchClockTime = System.currentTimeMillis();
    
    }
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mTimeoutPeriod;
        setBroadcastTimeoutLocked(timeoutTime);
    }
    
    final BroadcastOptions brOptions = r.options;
    final Object nextReceiver = r.receivers.get(recIdx);
    
    if (nextReceiver instanceof BroadcastFilter) {//动态注册receiver
        // Simple case: this is a registered receiver who gets
        // a direct call.
        BroadcastFilter filter = (BroadcastFilter)nextReceiver;
        deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
        if (r.receiver == null || !r.ordered) {
            r.state = BroadcastRecord.IDLE;
            scheduleBroadcastsLocked();
        } else {
            if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                scheduleTempWhitelistLocked(filter.owningUid,
                        brOptions.getTemporaryAppWhitelistDuration(), r);
            }
        }
        return;
    }
    
    // Hard case: need to instantiate the receiver, possibly
    // starting its application process to host it.
    
    ResolveInfo info =
        (ResolveInfo)nextReceiver;//静态注册的receiver
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);
    
    // This is safe to do even if we are skipping the broadcast, and we need
    // this information now to evaluate whether it is going to be allowed to run.
    final int receiverUid = info.activityInfo.applicationInfo.uid;
    // If it's a singleton, it needs to be the same app or a special app
    if (r.callingUid != Process.SYSTEM_UID && isSingleton
            && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
        info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
    }
    String targetProcess = info.activityInfo.processName;
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid, false);//获取当前静态注册receiver所在进程的ProcessRecord信息
    
    r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
    r.state = BroadcastRecord.APP_RECEIVE;
    r.curComponent = component;
    r.curReceiver = info.activityInfo;
    
    if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
        scheduleTempWhitelistLocked(receiverUid,
                brOptions.getTemporaryAppWhitelistDuration(), r);
    }
    
    // Broadcast is being executed, its package can't be stopped.
    try {
        AppGlobals.getPackageManager().setPackageStoppedState(
                r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
    }
    
    // Is this receiver's application already running?
    if (app != null && app.thread != null) {//若当前静态注册receiver所在进程存在
        try {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
            processCurBroadcastLocked(r, app);//处理当前串行广播BroadcastRecord
            return;
        } catch (RemoteException e) {
        } catch (RuntimeException e) {
            logBroadcastReceiverDiscardLocked(r);
            finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            scheduleBroadcastsLocked();
            // We need to reset the state if we failed to start the receiver.
            r.state = BroadcastRecord.IDLE;
            return;
        }
    
        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }
    
    // Not running -- get it started, to be executed when the app comes up.
    if ((r.curApp=mService.startProcessLocked(targetProcess,
            info.activityInfo.applicationInfo, true,
            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
            "broadcast", r.curComponent,
            (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                    == null) {
    
        logBroadcastReceiverDiscardLocked(r);
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE;
        return;
    }
    
    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;

      该部分的代码很长,就只分析没有任何异常发生,最简单的情况。
      就某一条有序广播,对该广播感兴趣的receiver有可能是动态注册也有可能是静态注册。对于动态的receiver而言,其处理过程同4.1小节的过程大致相同,这里就不说了;对于静态注册的receiver而言,就需要分两种情况来处理,一种情况是receiver所在进程已经启动了,另外一种情况就是receiver所在进程未启动。

    4.3.1 静态receiver所在进程已启动

    if (app != null && app.thread != null) {
        try {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
            processCurBroadcastLocked(r, app);
            return;
        } catch (RemoteException e) {
    
        } catch (RuntimeException e) {
    
        }
    
        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }

      很简单,这里不需要启动进程,直接进入BroadcastQueue.processCurBroadcastLocked。

    4.3.1.1 BroadcastQueue.processCurBroadcastLocked
    private final void processCurBroadcastLocked(BroadcastRecord r,
            ProcessRecord app) throws RemoteException {
    
        r.receiver = app.thread.asBinder();
        r.curApp = app;
        app.curReceiver = r;
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
        mService.updateLruProcessLocked(app, false, null);
        mService.updateOomAdjLocked();
    
        // Tell the application to launch this receiver.
        r.intent.setComponent(r.curComponent);
    
        boolean started = false;
        try {
            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                      PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                    mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                    app.repProcState);
    
            started = true;
        } finally {
        }
    4.3.1.2 ActivityThread.scheduleReceiver
    public final void scheduleReceiver(Intent intent, ActivityInfo info,
            CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
            boolean sync, int sendingUser, int processState) {
        updateProcessState(processState, false);
        ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                sync, false, mAppThread.asBinder(), sendingUser);
        r.info = info;
        r.compatInfo = compatInfo;
        sendMessage(H.RECEIVER, r);
    }

      注意,在发送有序广播给静态注册receiver时使用的是ReceiverData类,在发送有序广播给动态注册receiver时,使用的是ReceiverDispatcher类。
      通过消息机制,在handleMessage中。

    case RECEIVER:
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
        handleReceiver((ReceiverData)msg.obj);
        maybeSnapshot();
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    
        break;

      进入ActivityThread.handleReceiver。

    4.3.1.3 ActivityThread.handleReceiver
    private void handleReceiver(ReceiverData data) {
        ...
    
        IActivityManager mgr = ActivityManagerNative.getDefault();
    
        BroadcastReceiver receiver;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            data.intent.setExtrasClassLoader(cl);
            data.intent.prepareToEnterProcess();
            data.setExtrasClassLoader(cl);
            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
        } catch (Exception e) {
    
        }
    
        try {
            Application app = packageInfo.makeApplication(false, mInstrumentation);
    
    
    
            ContextImpl context = (ContextImpl)app.getBaseContext();
            sCurrentBroadcastIntent.set(data.intent);
            receiver.setPendingResult(data);
            receiver.onReceive(context.getReceiverRestrictedContext(),
                    data.intent);
        } catch (Exception e) {
    
        } finally {
            sCurrentBroadcastIntent.set(null);
        }
    
        if (receiver.getPendingResult() != null) {
            data.finish();
        }
    }

      这里后面的过程和4.1.64.1.7的过程大致相同,不过是ReceiverDispatcher换成了ReceiverData。会最终调用到ActivityManagerService.finishReceiver中。

    public void finishReceiver(IBinder who, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {
    
    
        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doNext = false;
            BroadcastRecord r;
    
            synchronized(this) {
                BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                        ? mFgBroadcastQueue : mBgBroadcastQueue;
                r = queue.getMatchingOrderedReceiver(who);
                if (r != null) {
                    doNext = r.queue.finishReceiverLocked(r, resultCode,
                        resultData, resultExtras, resultAbort, true);
                }
            }
    
            if (doNext) {
                r.queue.processNextBroadcast(false);
            }
            trimApplications();
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

      可以看到,如有必要,会继续调用BroadcastQueue.processNextBroadcast(),进入BroadcastQueue.processNextBroadcast()中4.2处理有序广播的地方时,是通过mOrderedBroadcasts.get(0)获取到的第一条有序广播,接着发送,从而完成有序广播的循环处理。

    4.3.2 静态receiver所在进程未启动

      对于进程未启动的情况,首要工作就是要将receiver所在进程启动起来。

    if ((r.curApp=mService.startProcessLocked(targetProcess,
            info.activityInfo.applicationInfo, true,
            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
            "broadcast", r.curComponent,
            (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                    == null) {
        // Ah, this recipient is unavailable.  Finish it if necessary,
        // and mark the broadcast record as ready for the next.
        Slog.w(TAG, "Unable to launch app "
                + info.activityInfo.applicationInfo.packageName + "/"
                + info.activityInfo.applicationInfo.uid + " for broadcast "
                + r.intent + ": process is bad");
        logBroadcastReceiverDiscardLocked(r);
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE;
        return;
    }
    
    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;

      由于进程启动比较耗时间,这里将正准备处理的有序广播保存在mPendingBroadcast中。在startProcessLocked过程中,正常情况下会执行到ActivityManagerService.attachApplicationLocked中。

    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            didSomething |= sendPendingBroadcastsLocked(app);
        } catch (Exception e) {
    
        }
    }
    boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        for (BroadcastQueue queue : mBroadcastQueues) {
            didSomething |= queue.sendPendingBroadcastsLocked(app);
        }
        return didSomething;
    }

    BroadcastQueue.sendPendingBroadcastsLocked

    public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        final BroadcastRecord br = mPendingBroadcast;
        if (br != null && br.curApp.pid == app.pid) {
            try {
                mPendingBroadcast = null;
                processCurBroadcastLocked(br, app);
                didSomething = true;
            } catch (Exception e) {
    
                logBroadcastReceiverDiscardLocked(br);
                finishReceiverLocked(br, br.resultCode, br.resultData,
                        br.resultExtras, br.resultAbort, false);
                scheduleBroadcastsLocked();
                // We need to reset the state if we failed to start the receiver.
                br.state = BroadcastRecord.IDLE;
                throw new RuntimeException(e.getMessage());
            }
        }
        return didSomething;
    }

      这个时候就拿出在进程完全启动好之前保存在mPendingBroadcast的有序广播,进行处理。

    aaaa
    点击跳转

    展开全文
  • android广播机制就是在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理。2.广播实现(自定义广播接受者和发送者)今天就用三个应用...

    1.什么是广播?

    android广播机制就是在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理。

    2.广播实现(自定义广播接受者和发送者)

    今天就用三个应用程序来模拟广播发送者和接收者,但是在实际开发中,都是系统是发送者,用户是接收者。条件有限,就用三个应用程序代替了,大家不要介意。

    广播分为有序广播和无需广播,下面我用的是无序广播

    发送者代码:
    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.example.android21_zhangkai_broadcastreceiver.MainActivity">
    
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/et_main_content"
            android:hint="请输入要发送的内容"
            />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="发送"
            android:onClick="send"
            />
    
    </LinearLayout>
    
    

    MainActivity.java

    package com.example.android21_zhangkai_broadcastreceiver;
    
    import android.content.Intent;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private EditText et_main_content;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            et_main_content = (EditText) findViewById(R.id.et_main_content);
        }
    
        public void send(View view){
    
            //获取输入的文本
            String content=et_main_content.getText().toString();
    
            //发送广播
            Intent intent=new Intent();
            //指定广播的名字
            intent.setAction("com.example.android21_zhangkai_broadcastreceiver.zk");
            //指定广播的内容
            intent.putExtra("content",content);
            //发送广播
            sendBroadcast(intent);
        }
    }
    
    

    广播接收者1号:

    MyReceiver01.java

    package com.example.android21_zhangkai_receiver01;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    /**
     * Created by Administrator on 2017/7/11 0011.
     */
    
    public class MyReceiver01 extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取广播的名字
            String action=intent.getAction();
            if("com.example.android21_zhangkai_broadcastreceiver.zk".equals(action)){
                //获取广播内容
                String content=intent.getStringExtra("content");
                Log.i("test","广播接受者1号:"+content);
            }
        }
    }
    
    

    注:在接收广播之前,我们需要注册一个广播
    而注册分两种:
    ①.静态注册
    ②.动态注册
    在这里我两种注册的方式都会讲,在接收者1号我就先用静态注册

    在配置文件内进行静态注册:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.android21_zhangkai_receiver01">
    
        <application android:allowBackup="true" android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true" android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <!--注册:广播接受者
            静态注册
            -->
            <receiver android:name=".MyReceiver01">
                <intent-filter>
                    <action android:name="com.example.android21_zhangkai_broadcastreceiver.zk"></action>
                </intent-filter>
            </receiver>
        </application>
    
    </manifest>
    

    广播接收者2号:

    MainActivity.java

    package com.example.android21_zhangkai_receiver02;
    
    import android.content.IntentFilter;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity {
    
        private MyReceiver02 myReceiver02;
        private IntentFilter intentFilter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            myReceiver02 = new MyReceiver02();
            intentFilter = new IntentFilter();
            intentFilter.addAction("com.example.android21_zhangkai_broadcastreceiver.zk");//.zk之前是包名
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            //注册广播
            registerReceiver(myReceiver02,intentFilter);
        }
    
    	//在动态注册中,一定要在Activity注销时注销注册,否则会报错
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //注销注册
            unregisterReceiver(myReceiver02);
        }
    }
    
    

    MyReceiver02.java

    package com.example.android21_zhangkai_receiver02;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    /**
     * Created by Administrator on 2017/7/11 0011.
     */
    
    public class MyReceiver02 extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取广播的名字
            String action=intent.getAction();
            if("com.example.android21_zhangkai_broadcastreceiver.zk".equals(action)){
                //获取广播内容
                String content=intent.getStringExtra("content");
                Log.i("test","广播接受者2号:"+content);
            }
        }
    }
    
    

    实现效果:
    这里写图片描述

    这里写图片描述

    有序广播
    有序广播与无序广播的最大区别就是,有序广播可以设置接收广播的优先级

    sendOrderedBroadcast(intent,null);//发送有序广播
    
    //接收有序广播
    //获取广播内容
    String content=intent.getStringExtra("content");
    

    //设置优先级

    <receiver android:name=".MyReceiver02">
                <intent-filter
                    android:priority="1000"
                    >
                    <!--priority的取值在-1000~1000之间,取值越大,优先级越高-->
                    <action android:name="com.zking.administrator.g160628_android21_sender.Hug"></action>
                </intent-filter>
            </receiver>
    

    当然有序广播还可以选择是否继续传播该广播
    使用abortBroadcast();即可

    还可以改变广播的内容

    //改变广播的内容
                //设置结果
                Bundle bundle=new Bundle();
                bundle.putString("newContent",content+",加油!");
                setResultExtras(bundle);//content是已经接收到的广播,我们可以使用这个方法添加内容
    

    Android常用的系统广播:
    //关闭或打开飞行模式时的广播
    Intent.ACTION_AIRPLANE_M;
    //充电状态,或者电池的电量发生变化;//电池的充电状态、电荷级别改变,不能通过组建声;
    Intent.ACTION_BATTERY_CH;
    //表示电池电量低
    Intent.ACTION_BATTERY_LO;
    //表示电池电量充足
    Intent.ACTION_BATTERY_OK;
    //关闭或打开飞行模式时的广播
    Intent.ACTION_AIRPLANE_MODE_CHANGED;
    //充电状态,或者电池的电量发生变化//电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册
    Intent.ACTION_BATTERY_CHANGED;
    //表示电池电量低
    Intent.ACTION_BATTERY_LOW;
    //表示电池电量充足,即从电池电量低变化到饱满时会发出广播
    Intent.ACTION_BATTERY_OKAY;
    //在系统启动完成后,这个动作被广播一次(只有一次)。
    Intent.ACTION_BOOT_COMPLETED;
    //按下照相时的拍照按键(硬件按键)时发出的广播
    Intent.ACTION_CAMERA_BUTTON;
    //当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息
    Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
    //设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java)
    Intent.ACTION_CONFIGURATION_CHANGED;
    //设备日期发生改变时会发出此广播
    Intent.ACTION_DATE_CHANGED;
    //设备内存不足时发出的广播,此广播只能由系统使用,其它APP不可用
    Intent.ACTION_DEVICE_STORAGE_LOW;
    //设备内存从不足到充足时发出的广播,此广播只能由系统使用,其它APP不可用
    Intent.ACTION_DEVICE_STORAGE_OK;
    //发出此广播的地方frameworks\base\services\java\com\android\server\DockObserver.java
    Intent.ACTION_DOCK_EVENT;
    //移动APP完成之后,发出的广播(移动是指:APP2SD)
    Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE;
    //正在移动APP时,发出的广播(移动是指:APP2SD)
    Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
    //Gtalk已建立连接时发出的广播
    Intent.ACTION_GTALK_SERVICE_CONNECTED;
    //Gtalk已断开连接时发出的广播
    Intent.ACTION_GTALK_SERVICE_DISCONNECTED;
    //在耳机口上插入耳机时发出的广播
    Intent.ACTION_HEADSET_PLUG;
    //改变输入法时发出的广播
    Intent.ACTION_INPUT_METHOD_CHANGED;
    //设备当前区域设置已更改时发出的广播
    Intent.ACTION_LOCALE_CHANGED;
    //表示用户和包管理所承认的低内存状态通知应该开始。
    Intent.ACTION_MANAGE_PACKAGE_STORAGE;
    //未正确移除SD卡(正确移除SD卡的方法:设置–SD卡和设备内存–卸载SD卡),但已把SD卡取出来时发出的广播 ,扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount)
    Intent.ACTION_MEDIA_BAD_REMOVAL;
    //按下"Media Button" 按键时发出的广播,假如有"Media Button" 按键的话(硬件按键)
    Intent.ACTION_MEDIA_BUTTON;
    //插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播?
    Intent.ACTION_MEDIA_CHECKING;
    //已拔掉外部大容量储存设备发出的广播(比如SD卡,或移动硬盘),不管有没有正确卸载都会发出此广播, 用户想要移除扩展介质(拔掉扩展卡)。
    Intent.ACTION_MEDIA_EJECT;
    //插入SD卡并且已正确安装(识别)时发出的广播, 扩展介质被插入,而且已经被挂载。
    Intent.ACTION_MEDIA_MOUNTED;
    //拓展介质存在,但使用不兼容FS(或为空)的路径安装点检查介质包含在Intent.mData领域。
    Intent.ACTION_MEDIA_NOFS;
    //外部储存设备已被移除,不管有没正确卸载,都会发出此广播, 扩展介质被移除。
    Intent.ACTION_MEDIA_REMOVED;
    //广播:已经扫描完介质的一个目录
    Intent.ACTION_MEDIA_SCANNER_FINISHED;
    //请求媒体扫描仪扫描文件并将其添加到媒体数据库。
    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE;
    //广播:开始扫描介质的一个目录
    Intent.ACTION_MEDIA_SCANNER_STARTED;
    // 广播:扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享。
    Intent.ACTION_MEDIA_SHARED;
    Intent.ACTION_MEDIA_UNMOUNTABLE;//
    // 广播:扩展介质存在,但是还没有被挂载 (mount)
    Intent.ACTION_MEDIA_UNMOUNTED
    Intent.ACTION_NEW_OUTGOING_CALL;
    //成功的安装APK之后//广播:设备上新安装了一个应用程序包。//一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
    Intent.ACTION_PACKAGE_ADDED;
    //一个已存在的应用程序包已经改变,包括包名
    Intent.ACTION_PACKAGE_CHANGED;
    //清除一个应用程序的数据时发出的广播(在设置--应用管理--选中某个应用,之后点清除数据时?)//用户已经清除一个包的数据,包括包名(清除包程序不能接收到这个广播)
    Intent.ACTION_PACKAGE_DATA_CLEARED;
    //触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用?
    Intent.ACTION_PACKAGE_INSTALL;
    //成功的删除某个APK之后发出的广播, 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
    Intent.ACTION_PACKAGE_REMOVED;
    //替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播?)
    Intent.ACTION_PACKAGE_REPLACED;
    //用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)
    Intent.ACTION_PACKAGE_RESTARTED;
    //插上外部电源时发出的广播
    Intent.ACTION_POWER_CONNECTED;
    //已断开外部电源连接时发出的广播
    Intent.ACTION_POWER_DISCONNECTED;
    Intent.ACTION_PROVIDER_CHANGED;//
    //重启设备时的广播
    Intent.ACTION_REBOOT;
    //屏幕被关闭之后的广播
    Intent.ACTION_SCREEN_OFF;
    //屏幕被打开之后的广播
    Intent.ACTION_SCREEN_ON;
    //关闭系统时发出的广播
    Intent.ACTION_SHUTDOWN;
    //时区发生改变时发出的广播
    Intent.ACTION_TIMEZONE_CHANGED;
    //时间被设置时发出的广播
    Intent.ACTION_TIME_CHANGED;
    //广播:当前时间已经变化(正常的时间流逝), 当前时间改变,每分钟都发送,不能通过组件声明来接收
    ,只有通过Context.registerReceiver()方法来注册
    Intent.ACTION_TIME_TICK;
    //一个用户ID已经从系统中移除发出的广播
    Intent.ACTION_UID_REMOVED;
    //设备已进入USB大容量储存状态时发出的广播?
    Intent.ACTION_UMS_CONNECTED;
    //设备已从USB大容量储存状态转为正常状态时发出的广播?
    Intent.ACTION_UMS_DISCONNECTED;
    Intent.ACTION_USER_PRESENT;//
    //设备墙纸已改变时发出的广播
    Intent.ACTION_WALLPAPER_CHANGED;

    总结:
    ①.动态注册的优先级高于静态注册

    下面是总结的思维导图:
    这里写图片描述

    展开全文
  • 一、广播发送者&广播接收者介绍 1.广播接收者 广播接收者简单地说就是接收广播意图的Java类,此Java类继承BroadcastReceiver类,重写: public void onReceive(Context context,Intent intent),其中...


    一、广播发送者&广播接收者介绍



    1.广播接收者


    广播接收者简单地说就是接收广播意图的Java类,此Java类继承BroadcastReceiver类,重写:

    public void onReceive(Context context,Intent intent),其中intent可以获得传递的数据;

    广播意图就是通过Context.sendBroadcast(Intent intent)或Context.sendOrderedBroadcast(Intent intent)发送的意图,通过这个语句,能够广播给所有满足条件的组件,比如intent设置了action="com.xiazdong",则所有在AndroidManifest.xml中设置过<action android:name="com.xiazdong"/>的广播接收者都能够接收到广播;


    :onReceive方法必须在10秒内完成,如果没有完成,则抛“Application No Response”当广播接收者onReceive方法需要执行很长时间时,最好将此耗时工作通过Intent发送给Service由Service完成,并且不能使用子线程解决,因为BroadcastReceiver是接收到广播后才创建的,并且生命周期很短,因此子线程可能在没有执行完就已经被杀死了。


    public void onReceive(Context context,Intent intent){
    	Intent intent = new Intent(context,XxxService.class);
    	context.startService(intent);
    }


    2.广播发送者


    通常广播发送方就是调用Context.sendBroadcast()的程序,而广播接收者就是继承BroadcastReceiver的程序;

    通常广播发送方都是通过隐式意图,这样才能发送给多人;


    广播发送方分为普通广播和有序广播;

    同步广播:发送方发出后,几乎同时到达多个广播接收者处,某个接收者不能接收到广播后进行一番处理后传给下一个接收者,并且无法终止广播继续传播;Context.sendBroadcast(intent);

    有序广播:广播接收者需要提前设置优先级,优先级高的先接收到广播,优先级数值为-1000~1000,在AndroidManifest.xml的<intent-filter android:priority="xxx">设置;比如存在3个广播接收者A、B、C,优先级A>B>C,因此A最先收到广播,当A收到广播后,可以向广播中添加一些数据给下一个接收者(intent.putExtra()),或者终止广播(abortBroadcast());Context.sendOrderedBroadcast(intent);



    二、广播接收者核心代码


    同步广播发送方核心代码:


    Intent intent = new Intent();
    intent.setAction("...");
    Context.sendBroadcast(intent);


    有序广播发送方核心代码:

    Intent intent = new Intent();
    intent.setAction("...");
    Context.sendOrderedBroadcast(intent,null);


    广播接收者核心代码:


    public class Receiver extends BroadcastReceiver{
    	public void onReceive(Context context, Intent intent) {
    		Bundle bundle = intent.getExtras();
    		...
    	}
    }

    AndroidManifest.xml

    <application>         
    	<receiver android:name=".Receiver"> 
    		<intent-filter android:priority="1000"> 
    			<action android:name="com.xiazdong"/>
    		</intent-filter>
    	</receiver>
    </application>		



    三、广播实例



    1.同步广播实例



    场景说明:




    (1)广播发送者:


    package com.xiazdong.broadcastsender;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    	private Button button;
    	private OnClickListener listener = new OnClickListener(){
    		@Override
    		public void onClick(View v) {
    			Intent intent = new Intent();
    			intent.setAction("com.xiazdong");
    			intent.putExtra("name", "xiazdong");
    			MainActivity.this.sendBroadcast(intent);
    			Toast.makeText(getApplicationContext(), "发送广播成功", Toast.LENGTH_SHORT).show();
    		}
    	};
    	@Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            button = (Button)this.findViewById(R.id.button);
            button.setOnClickListener(listener);
        }
    }


    (2)广播接收者


    package com.xiazdong.broadcastreceiver1;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    public class Receiver extends BroadcastReceiver {
    
    	@Override
    	public void onReceive(Context context, Intent intent) {
    		String name = intent.getExtras().getString("name");
    		Log.i("Recevier1", "接收到:"+name);
    	}
    
    }


    AndroidManifest.xml


    <receiver android:name=".Receiver">
            <intent-filter>
                 <action android:name="com.xiazdong"/>
            </intent-filter>
    </receiver>


    结果:





    2.有序广播实例



    场景说明:



    (1)广播发送者


    package com.xiazdong.broadcastsender;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    	private Button button;
    	private OnClickListener listener = new OnClickListener(){
    		@Override
    		public void onClick(View v) {
    			Intent intent = new Intent();
    			intent.setAction("com.xiazdong");
    			intent.putExtra("name", "xiazdong");
    			MainActivity.this.sendOrderedBroadcast(intent, null);	//有序广播发送
    			Toast.makeText(getApplicationContext(), "发送广播成功", Toast.LENGTH_SHORT).show();
    		}
    	};
    	@Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            button = (Button)this.findViewById(R.id.button);
            button.setOnClickListener(listener);
        }
    }


    (2)广播接收者


    Receiver1

    package com.xiazdong.broadcastreceiver1;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    public class Receiver extends BroadcastReceiver {
    
    	@Override
    	public void onReceive(Context context, Intent intent) {
    		String name = intent.getExtras().getString("name");
    		Log.i("Recevier1", "接收到:"+name);
    		abortBroadcast();	//Receiver1接收到广播后中断广播
    	}
    
    }


    AndroidManifest.xml


    <receiver android:name=".Receiver">
          <intent-filter android:priority="1000">	<!-- 设置最高优先级 -->
             <action android:name="com.xiazdong"/>
          </intent-filter>
     </receiver>













    展开全文
  • android中如何发送一个广播
  • Android发送自定义广播

    2019-01-21 14:23:54
    Android系统不仅存在系统级广播,用户也可以自定义广播Android系统中的广播可以分为两种类型:1.标准广播 2.有序广播。 1.标准广播  标准广播完全异步执行,在广播发出之后,所有的广播接收器几乎可以同时接收...
  • 广播作为android的四大组件之一,适用的地方还是很多,多用来特定条件情况下的通知。例如,开机,闹铃,电池电量过低等等。但还可以自定义广播,用来两个应用程序的通知。 曾经写的开机自启动的博客(通过接受系统...
  • Android广播的发送与接收效果图广播发送 广播分为有序广播和无序广播 有序广播与无序广播的区别 无序广播:只要是广播接收者指定了接收的事件类型,就可以接收到发送出来的广播消息。不能修改消息。 有序广播:...
  • 为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用 程序发出的广播,这样所有的安全性问题就都不...
  • 1.广播的发送者将一个特定类型的广播发送给ActivityManagerService。 2.AMS接收到这个广播后,首先找到与这个广播对应的广播接收者,然后将它们添加到一个广播调度队列中,再将这个调度队列传递BroadcastQueue,...
  • " adb shell am broadcast -a 你的广播 "打开命令行,输入如下指令:adb shell am broadcast -a android.intent.action.BOOT_COMPLETED该命令发送了一个开机完成的广播消息
  • 发送广播三种发送方法。 sendBroadcast(),sendOrderedBroadcast()和sendStickyBroadcast() sendBroadcast()这个方法的广播是能够发送给所有广播接收者,按照注册的先后顺序,如果你这个时候设置了广播接收者...
  • 1 广播类型 从广播的注册方式来分,分为以下2种:静态注册:通过&...lt;receiver&gt;&lt;/receiver&gt;... 上面静态广播和动态广播比较明显的3个区别:(1)静态广播在进程没有运行的时候,也可以收到,这时...
  • Android发送和接收广播

    2019-08-15 12:13:29
    1.前言 这是我(Android初学者)记的笔记,如果不对欢迎大佬指教。 ... Intent intent = new Intent("android....//加上这一句后就可以接收了(参数1:广播发送类的包名,参数2:广播接受者路径) intent.set...
  • 前面我们分析了Android应用程序注册广播接收器的过程,这个过程只完成了万里长征的...这就是本文要介绍的广播发送过程了。 广播的发送过程比广播接收器的注册过程要复杂得多了,不过这个过程仍然是以ActivityManagerSe
  • (1)无序广播是完全异步执行,发送广播时所有监听这个广播广播接收者都会收到此消息,但接收的顺序不确定。 (2)有序广播是按照接收者的优先级接收,只有一个广播接收者能接收信息,在此广播接收者中逻辑执行...
  • Android四大组件之一广播,使用的也比较多,广播可大致分为两种,一种是Android系统区域的广播,是由系统指令发出,例如:点亮屏幕广播,开机过程中的一些广播 省略…, 然而还有一种广播就是我们自己定义,自己来...
  • android广播发送与接收
  • 我们通常发送广播的时候是直接调用sendBroadcast(intent)方法发送的,但是我写APP的时候发现有时候这样发送广播无法接收到,之后发现如果使用LocalBroadcastManager.getInstance(context).sendBroadcast(intent);...
1 2 3 4 5 ... 20
收藏数 57,408
精华内容 22,963
关键字:

android 给广播发送消息