品茗论道说广播(Broadcast内部机制讲解)(下)

下面我们来看,递送广播动作中最重要的processNextBroadcast()。

3.2 最重要的processNextBroadcast()

从processNextBroadcast()的代码,我们就可以看清楚前面说的“平行广播”、“有序广播”和“动态receiver”、“静态receiver”之间的关系了。

我们在前文已经说过,所有的静态receiver都是串行处理的,而动态receiver则会按照发广播时指定的方式,进行“并行”或“串行”处理。能够并行处理的广播,其对应的若干receiver一定都已经存在了,不会牵扯到启动新进程的操作,所以可以在一个while循环中,一次性全部deliver。而有序广播,则需要一个一个地处理,其滚动处理的手段是发送事件,也就是说,在一个receiver处理完毕后,会利用广播队列(BroadcastQueue)的mHandler,发送一个BROADCAST_INTENT_MSG事件,从而执行下一次的processNextBroadcast()。

processNextBroadcast()的代码逻辑大体是这样的:先尝试处理BroadcastQueue中的“平行广播”部分。这需要遍历并行列表(mParallelBroadcasts)的每一个BroadcastRecord以及其中的receivers列表。对于平行广播而言,receivers列表中的每个子节点是个BroadcastFilter。我们直接将广播递送出去即可:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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);

    }

    . . . . . .

}

3.2.1 用deliverToRegisteredReceiverLocked()递送到平行动态receiver

deliverToRegisteredReceiverLocked()的代码截选如下:

【frameworks/base/services/java/com/android/server/am/BroadcastQueue.java】

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,

                                                     BroadcastFilter filter, 

                                                     boolean ordered) 

{

    . . . . . .

    . . . . . .

    if (!skip) 

    {

        if (ordered) 

        {

            r.receiver = filter.receiverList.receiver.asBinder();

            r.curFilter = filter;

            filter.receiverList.curBroadcast = r;

            r.state = BroadcastRecord.CALL_IN_RECEIVE;

            if (filter.receiverList.app != null

            {

                r.curApp = filter.receiverList.app;

                filter.receiverList.app.curReceiver = r;

                mService.updateOomAdjLocked();

            }

        }

        

            . . . . . .

            performReceiveLocked(filter.receiverList.app, 

                                 filter.receiverList.receiver,

                                 new Intent(r.intent), r.resultCode,

                                 r.resultData, r.resultExtras, 

                                 r.ordered, r.initialSticky);

            if (ordered) 

            {

                r.state = BroadcastRecord.CALL_DONE_RECEIVE;

            }

        

        . . . . . .

}

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,

        Intent intent, int resultCode, String data, Bundle extras,

        boolean ordered, boolean sticky) throws RemoteException 

{

    // Send the intent to the receiver asynchronously using one-way binder calls.

    if (app != null && app.thread != null

    {

        // If we have an app thread, do the call through that so it is

        // correctly ordered with other one-way calls.

        app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,

                data, extras, ordered, sticky);

    

    else

    {

        receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);

    }

}

终于通过app.thread向用户进程传递语义了。注意scheduleRegisteredReceiver()的receiver参数,它对应的就是前文所说的ReceiverDispatcher的Binder实体——InnerReceiver了。

总之,当语义传递到用户进程的ApplicationThread以后,走到:

?


1

2

3

4

5

6

7

8

9

// 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) throws RemoteException 

{

    receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);

}

终于走到ReceiverDispatcher的InnerReceiver了:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

static final class ReceiverDispatcher 

{

    final static class InnerReceiver extends IIntentReceiver.Stub 

    {

        . . . . . .

        . . . . . .

        public void performReceive(Intent intent, int resultCode,

                                   String data, Bundle extras, 

                                   boolean ordered, boolean sticky) 

        {

            LoadedApk.ReceiverDispatcher rd = mDispatcher.get();

            . . . . . .

            if (rd != null) {

                rd.performReceive(intent, resultCode, data, extras,

                                  ordered, sticky);

            

            . . . . . .

        }

    }

    . . . . . .

    public void performReceive(Intent intent, int resultCode,

                               String data, Bundle extras, 

                               boolean ordered, boolean sticky) 

    {

        . . . . . .

        Args args = new Args(intent, resultCode, data, extras, ordered, sticky);

        if (!mActivityThread.post(args)) // 请注意这一句!

        {

            if (mRegistered && ordered) 

            {

                IActivityManager mgr = ActivityManagerNative.getDefault();

                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,

                        "Finishing sync broadcast to " + mReceiver);

                args.sendFinished(mgr);

            }

        }

    }

}

请注意mActivityThread.post(args)一句,这样,事件泵最终会回调Args参数的run()成员函数:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

final class Args extends BroadcastReceiver.PendingResult implements Runnable 

{

    . . . . . .

    . . . . . .

    public void run() 

    {

        final BroadcastReceiver receiver = mReceiver;

        . . . . . .

        try {

            ClassLoader cl =  mReceiver.getClass().getClassLoader();

            intent.setExtrasClassLoader(cl);

            setExtrasClassLoader(cl);

            receiver.setPendingResult(this);

            receiver.onReceive(mContext, intent);  // 回调具体receiver的onReceive()

        catch (Exception e) {

            . . . . . .

        }

        

        if (receiver.getPendingResult() != null) {

            finish();

        }

        . . . . . .

    }

}

其中的那句receiver.onReceive(this),正是回调我们具体receiver的onReceive()成员函数的地方。噢,终于看到应用程序员熟悉的onReceive()了。这部分的示意图如下:

3.2.2 静态receiver的递送

说完动态递送,我们再来看静态递送。对于静态receiver,情况会复杂很多,因为静态receiver所从属的进程有可能还没有运行起来呢。此时BroadcastRecord节点中记录的子列表的节点是ResolveInfo对象。

?


1

2

3

4

ResolveInfo info = (ResolveInfo)nextReceiver;

. . . . . .

r.state = BroadcastRecord.APP_RECEIVE;

String targetProcess = info.activityInfo.processName;

那么我们要先找到receiver所从属的进程的进程名。

processNextBroadcast()中启动进程的代码如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

ProcessRecord app = mService.getProcessRecordLocked(targetProcess, 

info.activityInfo.applicationInfo.uid);

. . . . . .

if (app != null && app.thread != null

{

    . . . . . .

    app.addPackage(info.activityInfo.packageName);

    processCurBroadcastLocked(r, app);

    return;

    . . . . . .

}

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)

. . . . . .

mPendingBroadcast = r;

mPendingBroadcastRecvIndex = recIdx;

如果目标进程已经存在了,那么app.thread肯定不为null,直接调用processCurBroadcastLocked()即可,否则就需要启动新进程了。启动的过程是异步的,可能很耗时,所以要把BroadcastRecord节点记入mPendingBroadcast。

3.2.2.1 processCurBroadcastLocked()

我们先说processCurBroadcastLocked()。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

private final void processCurBroadcastLocked(BroadcastRecord r,

                        ProcessRecord app) throws RemoteException 

{

    . . . . . .

    r.receiver = app.thread.asBinder();

    r.curApp = app;

    app.curReceiver = r;

    . . . . . .

    . . . . . .

        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,

              mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),

              r.resultCode, r.resultData, r.resultExtras, r.ordered);

        . . . . . .

        started = true;

    . . . . . .

}

其中最重要的是调用app.thread.scheduleReceiver()的那句。在IApplicationThread接口中,是这样定义scheduleReceiver()函数原型的:

?


1

2

3

4

5

void scheduleReceiver(Intent intent, ActivityInfo info, 

                      CompatibilityInfo compatInfo,                      

                      int resultCode, String data, 

                      Bundle extras, boolean sync) 

                      throws RemoteException;

其中ActivityInfo info参数,记录着目标receiver的信息。可以看到,递送静态receiver时,是不会用到RecevierDispatcher的。

用户进程里handleMessage()

?


1

2

3

4

5

6

case RECEIVER:

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");

    handleReceiver((ReceiverData)msg.obj);

    maybeSnapshot();

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    

    break;

ActivityThread中,会运用反射机制,创建出BroadcastReceiver对象,而后回调该对象的onReceive()成员函数。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

private void handleReceiver(ReceiverData data) 

{

    . . . . . .

    IActivityManager mgr = ActivityManagerNative.getDefault();

    BroadcastReceiver receiver;

    try {

        java.lang.ClassLoader cl = packageInfo.getClassLoader();

        data.intent.setExtrasClassLoader(cl);

        data.setExtrasClassLoader(cl);

        receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();

    catch (Exception e) {

        . . . . . .

    }

    try {

        . . . . . .

        receiver.setPendingResult(data);

        receiver.onReceive(context.getReceiverRestrictedContext(), data.intent);

    catch (Exception e) {

        . . . . . .

    finally {

        sCurrentBroadcastIntent.set(null);

    }

    if (receiver.getPendingResult() != null) {

        data.finish();

    }

}

3.2.2.2 必要时启动新进程

现在我们回过头来看,在目标进程尚未启动的情况下,是如何完成递送的。刚刚我们已经看到调用startProcessLocked()的句子了,只要不出问题,目标进程成功启动后就会调用AMS的attachApplication()。

有关attachApplication()的详情,请参考其他关于AMS的文档,此处我们只需知道它里面又会调用attachApplicationLocked()函数。

?


1

private final boolean attachApplicationLocked(IApplicationThread thread, int pid)

attachApplicationLocked()内有这么几句:

?


1

2

3

4

5

6

7

8

9

// Check if a next-broadcast receiver is in this process...

if (!badApp && isPendingBroadcastProcessLocked(pid)) {

    try {

        didSomething = sendPendingBroadcastsLocked(app);

    catch (Exception e) {

        // If the app died trying to launch the receiver we declare it ‘bad‘

        badApp = true;

    }

}

它们的意思是,如果新启动的进程就是刚刚mPendingBroadcast所记录的进程的话,此时AMS就会执行sendPendingBroadcastsLocked(app)一句。

?


1

2

3

4

5

6

7

8

// The app just attached; send any pending broadcasts that it should receive

boolean sendPendingBroadcastsLocked(ProcessRecord app) {

    boolean didSomething = false;

    for (BroadcastQueue queue : mBroadcastQueues) {

        didSomething |= queue.sendPendingBroadcastsLocked(app);

    }

    return didSomething;

}

BroadcastQueue的sendPendingBroadcastsLocked()函数如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

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) {

            . . . . . .

        }

    }

    return didSomething;

}

可以看到,既然目标进程已经成功启动了,那么mPendingBroadcast就可以赋值为null了。接着,sendPendingBroadcastsLocked()会调用前文刚刚阐述的processCurBroadcastLocked(),其内再通过app.thread.scheduleReceiver(),将语义发送到用户进程,完成真正的广播递送。这部分在上一小节已有阐述,这里就不多说了。

3.2.3 说说有序广播是如何循环起来的?

我们知道,平行广播的循环很简单,只是在一个while循环里对每个动态receiver执行deliverToRegisteredReceiverLocked()即可。而对有序广播来说,原则上每次processNextBroadcast()只会处理一个BroadcastRecord的一个receiver而已。当然,此时摘下的receiver既有可能是动态注册的,也有可能是静态的。

对于动态注册的receiver,目标进程处理完广播之后,会间接调用am.finishReceiver()向AMS发出反馈,关于这一步,其实在前面罗列ReceiverDispatcher的performReceive()时已经出现过了,我们再列一下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public void performReceive(Intent intent, int resultCode,

                           String data, Bundle extras, 

                           boolean ordered, boolean sticky) 

{

    . . . . . .

    Args args = new Args(intent, resultCode, data, extras, ordered, sticky);

    if (!mActivityThread.post(args)) 

    {

        if (mRegistered && ordered) 

        {

            IActivityManager mgr = ActivityManagerNative.getDefault();

            . . . . . .

            args.sendFinished(mgr);  // 请注意这一句!

        }

    }

}

Args继承于BroadcastReceiver.PendingResult,它调用的sendFinished()就是PendingResult的sendFinished():

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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);

            else {

                // This broadcast was sent to a component; it is not ordered,

                // but we still need to tell the activity manager we are done.

                am.finishReceiver(mToken, 0nullnullfalse);

            }

        catch (RemoteException ex) {

        }

    }

}

代码中的am.finishReceiver()会通知AMS,表示用户侧receiver已经处理好了,或者至少告一段落了,请AMS进行下一步动作。

而对于动态注册的receiver,情况是类似的,最终也是调用am.finishReceiver()向AMS发出回馈的,只不过发起的动作是在ActivityThread的handleReceiver()动作中。前文已经列过这个函数了,大家注意下面的句子即可:

?


1

2

3

4

5

6

7

8

9

10

11

private void handleReceiver(ReceiverData data) 

{

        . . . . . .

        receiver.setPendingResult(data);

        receiver.onReceive(context.getReceiverRestrictedContext(),

                data.intent);

        . . . . . .

    if (receiver.getPendingResult() != null) {

        data.finish();

    }

}

ReceiverData也是继承于BroadcastReceiver.PendingResult的,它调用的finish()是PendingResult的finish():

?


1

2

3

4

5

6

7

8

9

10

11

public final void finish() 

{

    if (mType == TYPE_COMPONENT) {

        . . . . . .

    else if (mOrderedHint && mType != TYPE_UNREGISTERED) {

        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,

                "Finishing broadcast to " + mToken);

        final IActivityManager mgr = ActivityManagerNative.getDefault();

        sendFinished(mgr);

    }

}

此处的sendFinished()内部最终也会调用到am.finishReceiver(),向AMS通告receiver已经处理好了。

AMS侧在收到finishReceiver语义后,执行:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public void finishReceiver(IBinder who, int resultCode, String resultData,

        Bundle resultExtras, boolean resultAbort) 

{

    . . . . . .

    try {

        boolean doNext = false;

        BroadcastRecord r = null;

        synchronized(this) {

            r = broadcastRecordForReceiverLocked(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);

    }

}

可以看到,如有必要,会继续调用processNextBroadcast(),从而完成有序广播的循环处理。

3.2.4 说说有序广播的timeout处理

因为AMS很难知道一次广播究竟能不能完全成功递送出去,所以它必须实现一种“时限机制”。前文在阐述broadcastIntentLocked()时,提到过new一个BroadcastRecord节点,并插入一个BroadcastQueue里的“平行列表”或者“有序列表”。不过当时我们没有太细说那个BroadcastQueue,现在我们多加一点儿说明。

实际上系统中有两个BroadcastQueue,一个叫做“前台广播队列”,另一个叫“后台广播队列”,在AMS里是这样定义的:

?


1

2

BroadcastQueue mFgBroadcastQueue;

BroadcastQueue mBgBroadcastQueue;

为什么要搞出两个队列呢?我认为这是因为系统对“广播时限”的要求不同导致的。对于前台广播队列而言,它里面的每个广播必须在10秒之内把广播递送给receiver,而后台广播队列的时限比较宽,只需60秒之内递送到就可以了。具体时限值请看BroadcastQueue的mTimeoutPeriod域。注意,这个10秒或60秒限制是针对一个receiver而言的。比方说“前台广播队列”的某个BroadcastRecord节点对应了3个receiver,那么在处理这个广播节点时,只要能在30秒(3 x 10)之内搞定就可以了。事实上,AMS系统考虑了更多东西,所以它给一个BroadcastRecord的总时限是其所有receiver时限之和的2倍,在此例中就是60秒(2 x 3 x 10)。

对于平行receiver而言,时限的作用小一点儿,因为动态receiver是直接递送到目标进程的,它不考虑目标端是什么时候处理完这个广播的。

然而对于有序receiver来说,时限就比较重要了。因为receiver之间必须是串行处理的,也就是说上一个receiver在没处理完时,系统是不会让下一个receiver进行处理的。从processNextBroadcast()的代码来看,在处理有序receiver时,BroadcastRecord里的nextReceiver域会记录“下一个应该处理的receiver”的标号。只有在BroadcastRecord的所有receiver都处理完后,或者BroadcastRecord的处理时间超过了总时限的情况下,系统才会把这个BroadcastRecord节点从队列里删除。因此我们在processNextBroadcast()里看到的获取当前BroadcastRecord的句子是写死为r = mOrderedBroadcasts.get(0)的。

在拿到当前BroadcastRecord之后,利用nextReceiver值拿到当前该处理的receiver信息:

?


1

2

3

int recIdx = r.nextReceiver++;

. . . . . .

Object nextReceiver = r.receivers.get(recIdx);

当然,一开始,nextReceiver的值只会是0,表示第一个receiver有待处理,此时会给BroadcastRecord的dispatchTime域赋值。

?


1

2

3

4

5

6

int recIdx = r.nextReceiver++;

r.receiverTime = SystemClock.uptimeMillis();if (recIdx == 0) {

    r.dispatchTime = r.receiverTime;

    r.dispatchClockTime = System.currentTimeMillis();

    . . . . . .

}

也就是说,dispatchTime的意义是标记实际处理BroadcastRecord的起始时间,那么这个BroadcastRecord所能允许的最大时限值就是:

dispatchTime + 2 * mTimeoutPeriod * 其receiver总数

一旦超过这个时限,而BroadcastRecord又没有处理完,那么就强制结束这个BroadcastRecord节点:

?


1

2

3

4

5

6

7

8

if ((numReceivers > 0) &&

        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) 

{

    . . . . . .

    broadcastTimeoutLocked(false); // forcibly finish this broadcast

    forceReceive = true;

    r.state = BroadcastRecord.IDLE;

}

此处调用的broadcastTimeoutLocked()的参数是boolean fromMsg,表示这个函数是否是在处理“时限消息”的地方调用的,因为当前是在processNextBroadcast()函数里调用broadcastTimeoutLocked()的,所以这个参数为false。从这个参数也可以看出,另一处判断“处理已经超时”的地方是在消息处理机制里,在那个地方,fromMsg参数应该设为true。

大体上说,每当processNextBroadcast()准备递送receiver时,会调用setBroadcastTimeoutLocked()设置一个延迟消息:

?


1

2

3

long timeoutTime = r.receiverTime + mTimeoutPeriod;

. . . . . .

setBroadcastTimeoutLocked(timeoutTime);

setBroadcastTimeoutLocked()的代码如下:

?


1

2

3

4

5

6

7

8

final void setBroadcastTimeoutLocked(long timeoutTime) 

{    if (! mPendingBroadcastTimeoutMessage) 

    {

        Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);

        mHandler.sendMessageAtTime(msg, timeoutTime);

        mPendingBroadcastTimeoutMessage = true;

    }

}

只要我们的receiver能及时处理广播,系统就会cancel上面的延迟消息。这也就是说,但凡事件泵的handleMessage()开始处理这个消息,就说明receiver处理超时了。此时,系统会放弃处理这个receiver,并接着尝试处理下一个receiver。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

final Handler mHandler = new Handler() 

{

    public void handleMessage(Message msg) {

        switch (msg.what) 

        {

            . . . . . .

            case BROADCAST_TIMEOUT_MSG: 

            {

                synchronized (mService) 

                {

                    broadcastTimeoutLocked(true);

                }

            break;

        }

    }

};

broadcastTimeoutLocked()的代码截选如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

final void broadcastTimeoutLocked(boolean fromMsg) 

{

    if (fromMsg) {

        mPendingBroadcastTimeoutMessage = false;

    }

    if (mOrderedBroadcasts.size() == 0) {

        return;

    }

    long now = SystemClock.uptimeMillis();

    BroadcastRecord r = mOrderedBroadcasts.get(0);

    . . . . . .

    . . . . . .

    finishReceiverLocked(r, r.resultCode, r.resultData,

            r.resultExtras, r.resultAbort, true);

    scheduleBroadcastsLocked();

    . . . . . .

}

可以看到,当一个receiver超时后,系统会放弃继续处理它,并再次调用scheduleBroadcastsLocked(),尝试处理下一个receiver。

4 尾声

有关Android的广播机制,我们就先说这么多吧。品一杯红茶,说一段代码,管他云山雾罩,任那琐碎冗长,我自冷眼看安卓,瞧他修短随化。

转自http://blog.csdn.net/codefly/article/details/42323235

时间: 2024-10-10 01:44:01

品茗论道说广播(Broadcast内部机制讲解)(下)的相关文章

品茗论道说广播(Broadcast内部机制讲解)(上)

侯 亮 1 概述 我们在编写Android程序时,常常会用到广播(Broadcast)机制.从易用性的角度来说,使用广播是非常简单的.不过,这个不是本文关心的重点,我们希望探索得再深入一点儿.我想,许多人也不想仅仅停留在使用广播的阶段,而是希望了解一些广播机制的内部机理.如果是这样的话,请容我斟一杯红茶,慢慢道来. 简单地说,Android广播机制的主要工作是为了实现一处发生事情,多处得到通知的效果.这种通知工作常常要牵涉跨进程通讯,所以需要由AMS(Activity Manager Servi

《Android深入透析》之广播(Broadcast)

摘要 在android中,Broadcast作为四大组件之一,被广泛的应用在android程序之间的数据传递.举一个大家都比较熟悉的例子来说明.在车上的时候大家都有收听广播的习惯,广播电台通过发送不同频率的信号,然后大家通过将各自频率调成和电台相同的频率,就可以接受到广播内容了.在android中的广播其实是和这个是一样的效果的. 1.     概述 在android中,Broadcast作为四大组件之一,被广泛的应用在android程序之间的数据传递.举一个大家都比较熟悉的例子来说明.在车上的

zookeeper 内部机制学习

zookeeper 内部机制学习 1. zk的设计目标 最终一致性:client不论连接到那个Server,展示给它的都是同一个视图. 可靠性:具有简单.健壮.良好的性能.如果消息m被到一台服务器接收,那么消息m将被所有服务器接收. 实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息.但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口. 等待无关(wait-fr

[Spark內核] 第42课:Spark Broadcast内幕解密:Broadcast运行机制彻底解密、Broadcast源码解析、Broadcast最佳实践

本课主题 Broadcast 运行原理图 Broadcast 源码解析 Broadcast 运行原理图 Broadcast 就是将数据从一个节点发送到其他的节点上; 例如 Driver 上有一张表,而 Executor 中的每个并行执行的Task (100万个Task) 都要查询这张表的话,那我们通过 Broadcast 的方式就只需要往每个Executor 把这张表发送一次就行了,Executor 中的每个运行的 Task 查询这张唯一的表,而不是每次执行的时候都从 Driver 中获得这张表

Numppy | 10 广播(Broadcast)

广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行. 下面的图片展示了数组 b 如何通过广播来与数组 a 兼容. 4x3 的二维数组与长为 3 的一维数组相加,等效于把数组 b 在二维上重复 4 次再运算 如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘.这要求维数相同,且各维度的长度相同. import numpy as np

LTP 第一章 LTP介绍及内部机制

https://blog.csdn.net/yuanlaijike/article/details/78068331 LTP 第一章 LTP介绍及内部机制原创Jitwxs 发布于2017-09-23 03:21:58 阅读数 3993 收藏展开LTP系列链接: 第一章 LTP介绍及内部机制 第二章 开发Shell测试集 第三章 开发系统调用测试集 第四章 开发_exit()测试集 第五章 开发IO操作测试集 第六章 开发IO阻塞测试集 文章目录1.1 LTP介绍1.1.1 功能测试1.1.2 回

SQL Server 内存中OLTP内部机制概述(一)

----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory OLTP Internals Overview>:http://technet.microsoft.com/en-us/library/dn720242.aspx ----------------------------我是分割线------------------------------- SQL S

MYSQL的InnoDB Buffer Pool内部机制

1. 基本结构:INNODB用least recently used (LRU) 算法来管理他的buffer_pool. buffer_pool在内部被分隔为两个list. a young list 和 a old list. Young list 存储那些高频使用的缓存数据(默认占整个BUFFER的5/8) Old list 存储那些低频使用的数据(默认占整个BUFFER的3/8) 2.使用机制:当一个新块数据被从磁盘缓存到buffer当中,它默认被放在Old list的头部,即midpoin

委托的内部机制

委托是一种定义方法签名的类型,是对方法的抽象.封装.与委托的签名(由返回类型和参数组成)匹配的任何可访问类和结构中的任何方法都可以分配给该委托,方法可以是静态方法,也可以是实例方法.将一个方法绑定到委托时,C#和CLR允许引用类型的协变性和逆变性. 协变性是指方法的返回类型可以派生自委托的返回类型. 逆变性是指委托的参数类型可以派生自方法的参数类型. 协变性和逆变性只能用于引用类型,不能用于值类类型或void.所以不能将下面的方法与委托绑定: delegate Object DelegateCa