想象这样一种情景:自定义 View 需要在外界条件改变的时候,改变自己的状态,并且这个条件改变的同时会发送一条广播,那麽如何做呢?
在 android opensource: Settings 研究_android 组件如何响应语言变化 博客中,说过我会跟大家交流一下如何在自己定义的 View 中注册以及接收广播。
在贴代码之前,先看看 View 的两个回调方法 onAttachedToWindow、onDetachedFromWindow.
从 api 不难看出,onAttachedToWindow、onDetachedFromWindow 分别在 view 依附到 window、脱离 window 时回调。源码如下:
/**
* This is called when the view is attached to a window. At this point it
* has a Surface and will start drawing. Note that this function is
* guaranteed to be called before {@link #onDraw}, however it may be called
* any time before the first onDraw -- including before or after
* {@link #onMeasure}.
*
* @see #onDetachedFromWindow()
*/
protected void onAttachedToWindow() {
if ((mPrivateFlags & REQUEST_TRANSPARENT_REGIONS) != 0) {
mParent.requestTransparentRegion(this);
}
}
/**
* This is called when the view is detached from a window. At this point it
* no longer has a surface for drawing.
*
* @see #onAttachedToWindow()
*/
protected void onDetachedFromWindow() {
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
destroyDrawingCache();
}
还需要搞明白一个问题,onDraw 方法与这两个回调方法的调用顺序。
D/mark- ( 316): onAttachedToWindow()
D/mark- ( 316): onDraw()
D/mark- ( 316): onDetachedFromWindow()
当我们运行 App,然后退出 App(点击Back,或者kill,不是点击Home),调用顺序如上所示。
看一个 android 源码的例子:
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
可以看出,注册和取消注册广播的操作是在两个回调方法中完成的。
其中,mAttached 是定义的一个 boolean 值。这个地方值得借鉴学习!
private boolean mAttached;
接收并处理广播的逻辑在这里:
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
}
}
};
完整的源码,可以自行看
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
其中,CarrierLabel.java 是一个自定义的 TextView.
再延伸一步考虑,我们可以在这两个回调方法里面还可以发送广播、启动一个 android 组件等,希望对你有用!