WMS->視窗管理statusbar和navbar管理
要想讀懂窗口布局管理,必須瞭解status bar 和nav bar ,要了解這兩個bar 更要了解相關的flags,下面就會這些flags做一些說明
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //高亮狀態列
View.STATUS_BAR_TRANSLUCENT //半透明狀態列
View.STATUS_BAR_TRANSPARENT //透明狀態列,一般指定WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS系統會設定成全透明
View.SYSTEM_UI_FLAG_FULLSCREEN // 全屏顯示,隱藏狀態列和狀態列
View.STATUS_BAR_UNHIDE // 顯示狀態列,用於傳遞給systemui處理
View.NAVIGATION_BAR_TRANSPARENT //半透明導航欄
View.NAVIGATION_BAR_TRANSLUCENT //透明導航欄,一般指定WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS系統會設定成全透明
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // 隱藏導航欄
View.NAVIGATION_BAR_UNHIDE // 顯示狀態列,傳遞給systemui處理
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY //身臨其境的感覺,和SYSTEM_UI_FLAG_LIGHT_STATUS_BAR一起使用會隱藏狀態列和導航欄,從上面/下面滑出狀態列和導航欄,過幾秒自動消失
View.SYSTEM_UI_FLAG_IMMERSIVE //身臨其境的感覺,自動隱藏狀態列和導航欄,出上部/下部滑動狀態列出現,不自動隱藏
View.STATUS_BAR_TRANSIENT //進入瞬態,狀態列出來和隱藏的過程
View.NAVIGATION_BAR_TRANSIENT //進入瞬態,導航欄出來和隱藏的過程
WindowManager.LayoutParams.FLAG_FULLSCREEN //全屏顯示,隱藏狀態列
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS //導航欄狀態列透明,客戶端渲染狀態列導航欄背景
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND //強制導航欄狀態列透明,客戶端渲染狀態列導航欄背景
WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR //當此視窗到達頂部的時候保持前一個視窗的透明狀態
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS //指定半透明status bar
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION //指定半透明nav bar
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND 強制渲染背景色
下面這幾個狀態用於status bar 和nav bar 切換時候的瞬態過程
private static final int TRANSIENT_BAR_NONE = 0; //無任何狀態,當隱藏完成時候設定
private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1; // 請求顯示
private static final int TRANSIENT_BAR_SHOWING = 2; //正在顯示的過程
private static final int TRANSIENT_BAR_HIDING = 3; //正在隱藏的過程,隱藏完成window變成不可見,設定TRANSIENT_BAR_NONE
還要記住,分屏模式不允許隱藏bar
另外管理的還要注意幾個狀態,包括狀態列展開,鎖屏和鎖屏被阻斷,以及正常的全屏activity在前臺的幾種情況。
狀態列管理在wms這端的核心函式是PhoneWindowManager中的updateSystemUiVisibilityLw()函式
private int updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
//1 獲取焦點的window也就是能接收input事件的window
WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
return 0;
}
//2 如果當前焦點的window是ImmersiveModeConfirmation彈出的window不做處理,直接返回
if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
// The immersive mode confirmation should never affect the system bar visibility,
// otherwise it will unhide the navigation bar and hide itself.
winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
return 0;
}
}
final WindowState win = winCandidate;
//3 焦點window是keygurd,但是keygurd被阻斷,不處理直接返回
if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
// We are updating at a point where the keyguard has gotten
// focus, but we were last in a state where the top window is
// hiding it. This is probably because the keyguard as been
// shown while the top window was displayed, so we want to ignore
// it here because this is just a very transient change and it
// will quickly lose focus once it correctly gets hidden.
return 0;
}
//4 獲取win的標誌,處理rest flags
int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
}
//5 根據當前狀態處理SYSTEM_UI_FLAG_LIGHT_STATUS_BAR標誌(也就是status bar高亮狀態)
final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
//6 導航欄高亮狀態處理
final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
//7 獲取home stack和dock stack的大小
mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
//8 更新status bar 的屬性
final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
final int diff = visibility ^ mLastSystemUiFlags;
final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
//9 更新各屬性
final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
&& mFocusedApp == win.getAppToken()
&& mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
&& mLastDockedStackBounds.equals(mDockedStackBounds)) {
return 0;
}
mLastSystemUiFlags = visibility;
mLastFullscreenStackSysUiFlags = fullscreenVisibility;
mLastDockedStackSysUiFlags = dockedVisibility;
mLastFocusNeedsMenu = needsMenu;
mFocusedApp = win.getAppToken();
final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
final Rect dockedStackBounds = new Rect(mDockedStackBounds);
//10請求StatusBarManager處理(最終請求status bar 處理)
mHandler.post(new Runnable() {
@Override
public void run() {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
dockedVisibility, 0xffffffff, fullscreenStackBounds,
dockedStackBounds, win.toString());
statusbar.topAppWindowChanged(needsMenu);
}
}
});
return diff;
}
我們這裡對以上10個步驟進行解釋
1獲取候選的window,也就是接收事件的window,這裡可能有集中情況
(1)status bar 被展開或者keygurd的情況statusbar window是焦點的window
(2) 在分屏狀態下,接收事件的那個window
(3) 在沒有分屏狀態下全屏的activity就是焦點
對於這裡選擇的候選window,預設以焦點為主,沒有焦點時則使用mTopFullscreenOpaqueWindowState作為候選window,候選window用於使用它的flags處理系統bar的狀態。 如果沒有找到候選window 就直接返回。這裡解釋下mTopFullscreenOpaqueWindowState代表在full workspace stack上的activity
2 這裡處理的情況是當前的焦點window 是如下這個window
當處於身臨其境的模式,也就是設定了View.SYSTEM_UI_FLAG_IMMERSIVE |View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION標誌的時候,防止使用者恐慌,提示如何劃出狀態列導航欄,這種狀態不需要處理狀態列屬性,直接等到使用者退出幫助頁面後再去操作
3 當有一個window設定了WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED標誌的時候這個介面會在鎖屏上面顯示,這時候mHideLockScreen為真,注意這個標誌在8.0裡面改了這變數名,其實是一樣的。這種情況馬上焦點window就不是keygurd了,這只是焦點視窗切換的中間狀態,這種情況直接不處理,等狀態變了後再去處理
4 PolicyControl.getSystemUiVisibility(win, null)函式我們暫時怎為是直接獲取到win的systemUiVisibility變數所描述的關於該window設定的systemui的一些flags。
另外對於mResettingSystemUiFlags的解釋,當設定了View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_FULLSCREEN這連個標誌而沒有設定IMMERSIVE相關標誌的時候,會隱藏掉狀態列和導航欄,這時候要求點選螢幕任意地方,狀態列和導航欄都出出來,這個功能的實現是建立一個全屏的事件消費者去接收螢幕點選事件,當用戶點選後這個事件消費者會處理事件,事件消費者註冊的地方是在PhoneWindowManager的beginLayoutLw()函式中,事件的處理是在PhoneWindowManager的內部類HideNavInputEventReceiver的onInputEvent()方法中,讀者不妨自己去讀一下,主要是通過給mResettingSystemUiFlags設定View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN 這三個標誌,使status bar 出現來實現的。這個過程我們最後用一個情景棧去分析.
5 第五步是最終要的一步,前面的步驟都,用於更新systemui的一些標誌,由於函式比較長,我們稍後分析.
6 在一些場景下要對高亮標誌進行修正,我們這裡只拿statusbar 作為例子說明
private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
? mStatusBar
: opaqueOrDimming;
if (statusColorWin != null) {
if (statusColorWin == opaque) {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect
// its light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
& View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else if (statusColorWin != null && statusColorWin.isDimming()) {
// Otherwise if it's dimming, clear the light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
}
return vis;
}
程式碼很簡單,首先選擇statusColorWin,規則是如果是keygurd且不被其他window覆蓋則選擇statusbar 作為statusColorWin,否則就是使用引數opaqueOrDimming(放在full stack中的), 當statusColorWin為opaque的window的時候(也就是full stack中不透明的window),這時候狀態列的高亮狀態由opaque window決定. 如果不是full stack中的opaque window 則由window自身的Dimming狀態決定
7 獲取Home stack 和docker stack的大小儲存在mNonDockedStackBounds,mDockedStackBounds變數中
8,9 更新我們計算好的systemui相關的屬性
10請求StatusBarManager處理(最終請求Systemui 處理)
這裡第五條和第十條我們分別展開說明
首先第五步驟更新systemuiFlags的過程,這個過程主要參考焦點window,mTopFullscreenOpaqueWindowState和mTopDockedOpaqueWindowState去計算bar的屬性
private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID);
final boolean freeformStackVisible =
mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID);
final boolean resizing = mWindowManagerInternal.isDockedDividerResizing();
// We need to force system bars when the docked stack is visible, when the freeform stack
// is visible but also when we are resizing for the transitions when docked stack
// visibility changes.
//1 判斷是否強制顯示system bar
mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
//2 計算fullscreenTransWin用於計算bar 的透明情況
// apply translucent bar vis flags
WindowState fullscreenTransWin = isStatusBarKeyguard() && !mHideLockScreen
? mStatusBar
: mTopFullscreenOpaqueWindowState;
//3 計算狀態列透明flags
vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
//4 計算導航欄透明情況
vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
//5 計算docker導航欄透明度
final int dockedVis = mStatusBarController.applyTranslucentFlagLw(
mTopDockedOpaqueWindowState, 0, 0);
//6 根據mTopFullscreenOpaqueWindowState計算fullscreen stack的FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS標誌
final boolean fullscreenDrawsStatusBarBackground =
(drawsSystemBarBackground(mTopFullscreenOpaqueWindowState)
&& (vis & View.STATUS_BAR_TRANSLUCENT) == 0)
|| forcesDrawStatusBarBackground(mTopFullscreenOpaqueWindowState);
//7 根據dockedDrawsStatusBarBackground計算docker stack的FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS標誌
final boolean dockedDrawsStatusBarBackground =
(drawsSystemBarBackground(mTopDockedOpaqueWindowState)
&& (dockedVis & View.STATUS_BAR_TRANSLUCENT) == 0)
|| forcesDrawStatusBarBackground(mTopDockedOpaqueWindowState);
// prevent status bar interaction from clearing certain flags
int type = win.getAttrs().type;
boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
//8 根據status 是否展開清除一些屬性
if (statusBarHasFocus && !isStatusBarKeyguard()) {
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
if (mHideLockScreen) {
flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
}
vis = (vis & ~flags) | (oldVis & flags);
}
//9 根據FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS設定一些屬性
if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
vis |= View.STATUS_BAR_TRANSPARENT;
vis &= ~View.STATUS_BAR_TRANSLUCENT;
} else if ((!areTranslucentBarsAllowed() && fullscreenTransWin != mStatusBar)
|| forceOpaqueStatusBar) {
vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
}
//10 設定導航欄的透明度
vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);
// update status bar
boolean immersiveSticky =
(vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
final boolean hideStatusBarWM =
mTopFullscreenOpaqueWindowState != null
&& (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
& WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
final boolean hideStatusBarSysui =
(vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
final boolean hideNavBarSysui =
(vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
final boolean transientStatusBarAllowed = mStatusBar != null
&& (statusBarHasFocus || (!mForceShowSystemBars
&& (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
final boolean transientNavBarAllowed = mNavigationBar != null
&& !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
//11 根據使用者是否進入恐慌狀態顯示bar
final long now = SystemClock.uptimeMillis();
final boolean pendingPanic = mPendingPanicGestureUptime != 0
&& now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard() && mKeyguardDrawComplete) {
// The user performed the panic gesture recently, we're about to hide the bars,
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
mStatusBarController.showTransient();
if (!isNavBarEmpty(vis)) {
mNavigationBarController.showTransient();
}
}
final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
&& !transientStatusBarAllowed && hideStatusBarSysui;
final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
&& !transientNavBarAllowed;
//12 不能隱藏bar 設定flags
if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
// clear the clearable flags instead
clearClearableFlagsLw();
vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
}
final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
final boolean navAllowedHidden = immersive || immersiveSticky;
//13 根據window型別顯示導航欄
if (hideNavBarSysui && !navAllowedHidden && windowTypeToLayerLw(win.getBaseType())
> windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
// We can't hide the navbar from this window otherwise the input consumer would not get
// the input events.
vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
//14 更新status bar 可見性
vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
// update navigation bar
boolean oldImmersiveMode = isImmersiveMode(oldVis);
boolean newImmersiveMode = isImmersiveMode(vis);
//15 身臨其境狀態發生變化,處理
if (win != null && oldImmersiveMode != newImmersiveMode) {
final String pkg = win.getOwningPackage();
mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()));
}
//16 更系導航欄可見性
vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
return vis;
}
1 判斷是否強制顯示system bar ,當freedom stack和docker stack存在或者正在拖拽改變大小的情況,強制顯示system bar
2 計算fullscreenTransWin用於計算bar 的透明情況,這裡可以看出來總是以statusbar window 和mTopFullscreenOpaqueWindowState計算全域性的bar 狀態
3 使用fullscreenTransWin計算狀態列透明標誌
public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
if (mWin != null) {
if (win != null && (win.getAttrs().privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
int fl = PolicyControl.getWindowFlags(win, null);
if ((fl & mTranslucentWmFlag) != 0) {
vis |= mTranslucentFlag;
} else {
vis &= ~mTranslucentFlag;
}
if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
vis |= mTransparentFlag;
} else {
vis &= ~mTransparentFlag;
}
} else {
vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
vis = (vis & ~mTransparentFlag) | (oldVis & mTransparentFlag);
}
}
return vis;
}
這裡如果PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR標誌被設定則繼承之前的標誌,對於status bar 這裡主要根據WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS設定View.STATUS_BAR_TRANSLUCENT(看來是為了相容老版本) ,根據WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS設定View.STATUS_BAR_TRANSPARENT狀態. 一個代表半透明,一個代表透明.
4 計算導航欄透明情況,這裡和3是很相似的就不去介紹了
5 計算docker導航欄透明度
6 根據mTopFullscreenOpaqueWindowState 和FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS標誌計算fullscreen stack是否允許客戶端自己繪製狀態列的顏色,這裡可以看出如果設定了狀態列半透明,是不允許客戶端繪製狀態列顏色的,注意客戶端如果設定了WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS就會設定View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,這時候狀態列就應該隱藏,所以不需要使用客戶端渲染狀態列背景色. 除非客戶端強制渲染背景色,也就是PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND標誌成立
7 和6類似,只不過是計算docker stack的狀態
8 如果當前status bar 獲取焦點,要去掉一些標誌
int type = win.getAttrs().type;
boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
if (statusBarHasFocus && !isStatusBarKeyguard()) {
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
if (mHideLockScreen) {
flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
}
vis = (vis & ~flags) | (oldVis & flags);
}
這裡可以看出,對於這些標誌不做更改,還是使用之前的標誌.所以status bar 設定這些標誌是不生效的.
9 在步驟6中計算出來docker stack和full stack是否需要使用客戶端渲染status bar 背景色,如果二者都需要客戶端渲染背景色,設定狀態列背景為透明的,去掉辦透明的設定,如果status bar 只能設定為不透明的話,其掉View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT標誌. 所以記住這裡View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT是有可能並存的
10 設定導航欄的透明度
private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
boolean freeformStackVisible, boolean isDockedDividerResizing) {
if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
visibility = setNavBarOpaqueFlag(visibility);
}
} else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
if (isDockedDividerResizing) {
visibility = setNavBarOpaqueFlag(visibility);
} else if (freeformStackVisible) {
visibility = setNavBarTranslucentFlag(visibility);
} else {
visibility = setNavBarOpaqueFlag(visibility);
}
}
if (!areTranslucentBarsAllowed()) {
visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
}
return visibility;
}
這裡主要根據一些配置的屬性設定導航蘭透明情況
11 根據使用者是否進入恐慌狀態顯示bar
boolean immersiveSticky =
(vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
final boolean hideStatusBarWM =
mTopFullscreenOpaqueWindowState != null
&& (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
& WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
final boolean hideStatusBarSysui =
(vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
final boolean hideNavBarSysui =
(vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
final boolean transientStatusBarAllowed = mStatusBar != null
&& (statusBarHasFocus || (!mForceShowSystemBars
&& (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
final boolean transientNavBarAllowed = mNavigationBar != null
&& !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
介紹11 之前先看看這些變數的含義. SYSTEM_UI_FLAG_IMMERSIVE_STICKY標誌的含義我們最開始已經看到了,hideStatusBarWM代表full stack中不透明的window是否設定了FLAG_FULLSCREEN標誌,用於隱藏狀態列
hideStatusBarSysui代表full stack中不透明的window是否設定了SYSTEM_UI_FLAG_FULLSCREEN,用於隱藏狀態列
hideNavBarSysui代表是否要隱藏導航欄目,通過View.SYSTEM_UI_FLAG_HIDE_NAVIGATION標誌確定
transientStatusBarAllowed代表status bar 是否允許進入到順態,也就是從隱藏到顯示的一個切換狀態. 這裡有一下幾種情況可以進入瞬態
- 1 status bar 為焦點window
- 2不強制顯示status bar 並且設定了WindowManager.LayoutParams.FLAG_FULLSCREEN標誌
- 3不強制顯示status bar 並且設定了View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN
看來2和3標誌所產生的效果是一樣的
在來看11,當用戶5s內連續按power鍵,先熄滅螢幕,再點亮螢幕,有可能是由於狀態看和導航來都關閉了,引起使用者的恐慌,這裡如果發現是這種情況,使狀態列和導航欄進入舜態,從螢幕兩端移出來,showTransient()函式我們一會分析,這裡注意引起恐慌的還是應該為導航欄不可見,如果導航蘭可見也不會使狀態列進入舜態,另外11這種情況不會管transientStatusBarAllowed和transientNavBarAllowed條件是否成立
12 不能隱藏bar 設定flags
final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
&& !transientStatusBarAllowed && hideStatusBarSysui;
final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
&& !transientNavBarAllowed;
這裡前面計算了兩個變數,如果已經請求了進入瞬態,或者允許進入瞬態,這兩種情況都不為真,就不允許進入瞬態,就會設定denyTransientStatus,denyTransientNav,不能進入瞬態,要設定mResettingSystemUiFlags|=SYSTEM_UI_CLEARABLE_FLAGS,通知客戶端清除這些標誌,然後也清除我們要通知給systemui的這些標誌
13 不允許隱藏狀態列,清除View.SYSTEM_UI_FLAG_HIDE_NAVIGATION標誌
14 更新狀態列顯示狀態mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);我們一會分析
15 View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 標誌發生變化,使用 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()))更新狀態,mImmersiveModeConfirmation只是用於控制下面window的顯示
16 mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis)更新狀態列顯示狀態
到這裡看完了全域性visible的更新,我們就來看下StatusBarController的使用,目前位置我們基本上遇到的就兩個函式
1mStatusBarController.showTransient(); 使請求status bar 進入瞬態
2 mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis) 更新顯示狀態
public void showTransient() {
if (mWin != null) {
setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
}
}
private void setTransientBarState(int state) {
if (mWin != null && state != mTransientBarState) {
if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
mLastTranslucent = SystemClock.uptimeMillis();
}
mTransientBarState = state;
if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
}
}
函式很簡單,只是把mTransientBarState設定為TRANSIENT_BAR_SHOW_REQUESTED狀態,表示請求瞬態
再來看下updateVisibilityLw函式
public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
//1 status bar 對應的window不存在,直接返回
if (mWin == null) return vis;
//2 需要進入舜態的處理
if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
if (transientAllowed) { //3 允許進入瞬態
vis |= mTransientFlag; //4 設定View.STATUS_BAR_TRANSIENT狀態表示進入瞬態
if ((oldVis & mTransientFlag) == 0) {
//5首次設定View.STATUS_BAR_TRANSIENT告訴systemui
//準備好了顯示,設定View.STATUS_BAR_UNHIDE標誌
vis |= mUnhideFlag; // tell sysui we're ready to unhide
}
//6 更新為TRANSIENT_BAR_SHOWING狀態
setTransientBarState(TRANSIENT_BAR_SHOWING); // request accepted
} else {
//7 不允許進入瞬態,設定為TRANSIENT_BAR_NONE狀態
setTransientBarState(TRANSIENT_BAR_NONE); // request denied
}
}
if (mShowTransparent) { //8 設定status bar 可見,注意這裡不一定是瞬態的
vis |= mTransparentFlag;
if (mSetUnHideFlagWhenNextTransparent) {
vis |= mUnhideFlag;
mSetUnHideFlagWhenNextTransparent = false;
}
}
if (mTransientBarState != TRANSIENT_BAR_NONE) { //9 如果狀態不是NONE不允許LOW_PROFILE(淡化)模式顯示
vis |= mTransientFlag; // ignore clear requests until transition completes
vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile
}
//10 更新最後不是半透明的時間
if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
((vis | oldVis) & mTransparentFlag) != 0) {
mLastTranslucent = SystemClock.uptimeMillis();
}
return vis;
}
準備了這麼多標誌,最終都是要作用在客戶端和System ui上,我們這裡就看看如何通知給system ui
statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
dockedVisibility, 0xffffffff, fullscreenStackBounds,
dockedStackBounds, win.toString());
statusbar.topAppWindowChanged(needsMenu);
該方法在StatusBarManagerService中實現
private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
Rect fullscreenBounds, Rect dockedBounds, String cause) {
// also allows calls from window manager which is in this process.
//1 檢查許可權
enforceStatusBarService();
if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
synchronized (mLock) {
//2 更新SystemUI
updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
fullscreenBounds, dockedBounds);
//3 更新system ui disable 狀態(DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
//| DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
// | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
// | DISABLE_SEARCH;) 我們不關心這些不作分析
disableLocked(
mCurrentUserId,
vis & StatusBarManager.DISABLE_MASK,
mSysUiVisToken,
cause, 1);
}
}
private void updateUiVisibilityLocked(final int vis,
final int fullscreenStackVis, final int dockedStackVis, final int mask,
final Rect fullscreenBounds, final Rect dockedBounds) {
//1 判斷狀態是否發生變化
if (mSystemUiVisibility != vis
|| mFullscreenStackSysUiVisibility != fullscreenStackVis
|| mDockedStackSysUiVisibility != dockedStackVis
|| !mFullscreenStackBounds.equals(fullscreenBounds)
|| !mDockedStackBounds.equals(dockedBounds)) {
//2 記錄最終狀態,方便下一次比較狀態是否發生變化
mSystemUiVisibility = vis;
mFullscreenStackSysUiVisibility = fullscreenStackVis;
mDockedStackSysUiVisibility = dockedStackVis;
mFullscreenStackBounds.set(fullscreenBounds);
mDockedStackBounds.set(dockedBounds);
mHandler.post(new Runnable() {
public void run() {
if (mBar != null) {
try {
//3 通知systemui 狀態變化
mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
mask, fullscreenBounds, dockedBounds);
} catch (RemoteException ex) {
}
}
}
});
}
}
函式有七個引數,其中
vis表示計算出來的全域性的bar的flags,fullscreenStackVis表示full stactk決定的SYSTEM_UI_FLAG_LIGHT_STATUS_BAR狀態
dockedStackVis則表示dock stack的SYSTEM_UI_FLAG_LIGHT_STATUS_BAR狀態
Rect fullscreenBounds, Rect dockedBounds分別表示full stack大小和docker stack大小
函式在上面程式碼的註釋中已經分析清楚,我們重點來看Systemui 中的處理
mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
mask, fullscreenBounds, dockedBounds);
函式在SystemUI的PhoneStatusBar中,8.0這個類已經去掉,在哪我沒有看,這裡引數和StatusBarManagerService類中的同名函式幾乎是一致的,這裡不再詳細說明
@Override // CommandQueue
public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
//1 只計算mask影響的位的變化
final int oldVal = mSystemUiVisibility;
final int newVal = (oldVal&~mask) | (vis&mask);
final int diff = newVal ^ oldVal;
if (DEBUG) Log.d(TAG, String.format(
"setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
Integer.toHexString(vis), Integer.toHexString(mask),
Integer.toHexString(oldVal), Integer.toHexString(newVal),
Integer.toHexString(diff)));
boolean sbModeChanged = false;
if (diff != 0) {//2 發生變化做處理
//3 更新標誌
mSystemUiVisibility = newVal;
//3 更新low profile的狀態,其實就是更新id為notification_lights_out的view的alpha
// update low profile
if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
setAreThereNotifications();
}
// ready to unhide
//4 設定STATUS_BAR_UNHIDE標誌
if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
mNoAnimationOnNextBarModeChange = true;
}
//5計算bar顯示的屬性
// update status bar mode
final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,
View.STATUS_BAR_TRANSPARENT);
//6 計算導航欄模式
// update navigation bar mode
final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
oldVal, newVal, mNavigationBarView.getBarTransitions(),
View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
View.NAVIGATION_BAR_TRANSPARENT);
sbModeChanged = sbMode != -1;
final boolean nbModeChanged = nbMode != -1;
boolean checkBarModes = false;
//7 更新status bar 模式
if (sbModeChanged && sbMode != mStatusBarMode) {
mStatusBarMode = sbMode;
checkBarModes = true;
}
//8 跟新nav bar 模式
if (nbModeChanged && nbMode != mNavigationBarMode) {
mNavigationBarMode = nbMode;
checkBarModes = true;
}
//9 導航欄或者狀態列模式發生變化,切換模式
if (checkBarModes) {
checkBarModes();
}
//10 模式發生變化
if (sbModeChanged || nbModeChanged) {
// update transient bar autohide
if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
//11 三秒後移動隱藏
scheduleAutohide();
} else {
//12 取消自動隱藏
cancelAutohide();
}
}
if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
}
//13 通知狀態列狀態發生變化
// send updated sysui visibility to window manager
notifyUiVisibilityChanged(mSystemUiVisibility);
}
mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
}
5 計算bar 顯示的屬性
private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
: (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
: (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
: (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
: (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
: MODE_OPAQUE;
}
這裡主要有五個屬性
1 MODE_SEMI_TRANSPARENT由不顯示到顯示的過程中,這種是完全透明的status bar ,不影響應用的content顯示
2 MODE_TRANSLUCENT 半透明的,這種應該隱藏狀態列
3 View.SYSTEM_UI_FLAG_LOW_PROFILE | View.STATUS_BAR_TRANSPARENT 低亮度但是狀態列透明,客戶端渲染顏色,這種情況並不覆蓋在應用的content上
4 MODE_TRANSPARENT 透明,客戶端渲染背景
5 MODE_LIGHTS_OUT 低亮
6 不透明
知道這些後systemui 這邊的設計也非常簡單的理解了. 那麼我們再來看看 notifyUiVisibilityChanged(mSystemUiVisibility);通知給WMS後會做什麼
在WindowManagerService中的statusBarVisibilityChanged函式中處理
@Override
public void statusBarVisibilityChanged(int visibility) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Caller does not hold permission "
+ android.Manifest.permission.STATUS_BAR);
}
synchronized (mWindowMap) {
//1 更新最終狀態
mLastStatusBarVisibility = visibility;
//2 計算PhoneWindowMananger中的狀態
visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
//3 更新客戶端狀態
updateStatusBarVisibilityLocked(visibility);
}
}
我們就來按照上面三步去分析
步驟1很簡單就不說了
2 PhoneWindowMananger->adjustSystemUiVisibilityLw
@Override
public int adjustSystemUiVisibilityLw(int visibility) {
//1 更新status bar 屬性
mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
// Reset any bits in mForceClearingStatusBarVisibility that
// are now clear.
mResettingSystemUiFlags &= visibility;
// Clear any bits in the new visibility that are currently being
// force cleared, before reporting it.
//3 清除visibility中包含的mResettingSystemUiFlags|mForceClearedSystemUiFlags屬性
return visibility & ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
}
- 1 adjustSystemUiVisibilityLw 這個函式只是向status bar的另一個狀態切換,請參考最前面說明的瞬態狀態
- 2 清除已經設定好的mResettingSystemUiFlags中的標誌
3 清除那些無用要清除的標誌返回
3 WindowManagerService->updateStatusBarVisibilityLocked(visibility)函式
boolean updateStatusBarVisibilityLocked(int visibility) {
//1 沒有變化直接返回
if (mLastDispatchedSystemUiVisibility == visibility) {
return false;
}
//2 變化的標誌
final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
// We are only interested in differences of one of the
// clearable flags...
& View.SYSTEM_UI_CLEARABLE_FLAGS
// ...if it has actually been cleared.
& ~visibility;
mLastDispatchedSystemUiVisibility = visibility;
mInputManager.setSystemUiVisibility(visibility);
//3 獲取主螢幕上的window
final WindowList windows = getDefaultWindowListLocked();
final int N = windows.size();
for (int i = 0; i < N; i++) {
WindowState ws = windows.get(i);
try {
int curValue = ws.mSystemUiVisibility;
int diff = (curValue ^ visibility) & globalDiff;
int newValue = (curValue&~diff) | (visibility&diff);
if (newValue != curValue) {
ws.mSeq++;
ws.mSystemUiVisibility = newValue;
}
if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
//4 標誌發生變化,通知客戶端變化
ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
visibility, newValue, diff);
}
} catch (RemoteException e) {
// so sorry
}
}
return
相關推薦
WMS->視窗管理statusbar和navbar管理
要想讀懂窗口布局管理,必須瞭解status bar 和nav bar ,要了解這兩個bar 更要了解相關的flags,下面就會這些flags做一些說明
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //高亮狀態列
View.STATUS_BAR_TRANS
WMS->視窗管理statusbar和navbar管理
要想讀懂窗口布局管理,必須瞭解status bar 和nav bar ,要了解這兩個bar 更要了解相關的flags,下面就會這些flags做一些說明
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //高亮狀態列
View.
監控客戶機-新增主機、管理模板、管理圖形和視窗
監控客戶機-新增主機
服務端zabbix-server和zabbix-agent都
5.13-15監控客戶機新增主機,管理模板,管理圖形和視窗
開發十年,就只剩下這套架構體系了!
>>>
STL淺析——序列式容器vector的構造和內存管理: constructor() 和 push_back()
技術 eal ace name des 分享 names private rst 咱們先來做一個測試capacity是容器容量,size是大小:
#include <iostream>
#include <vector>
using names
iptables實用教程(二):管理鏈和策略
否則 命令顯示 accept 目的 number cep 存在 當前 末尾 概念和原理請參考上一篇文章“iptables實用教程(一)”。
本文講解如果管理iptables中的鏈和策略。
下面的代碼格式中,下劃線表示是一個占位符,需要根據實際情況輸入參數,不帶下劃線的表示是
WAS 管理節點和node同步報錯
system request generate 同步WAS管理節點和node報如下錯誤:[17-5-28 20:42:04:546 CST] 00000082 NodeSync E ADMS0005E: The system is unable to generate synchro
unity5打包機制下,一種資源打ab和資源管理的方案
remove 自己 return game tor 基礎 resource mea easyn unity5打包機制下,一種資源打ab和資源管理的方案。1.打ab: 1.設置平臺 2.清楚所有資源的assetbundlename: string[] abN
異常和狀態管理1
開始 代碼 發生 一個 狀態管理 code argument pla 關鍵字 異常是指成員沒有完成它的名稱所宣稱的行動。
如 FileStream 的 方法裏有 Read,Write,等等(行動成員通常用動詞表示)。當行動成員不能完成任務時,就應拋出異常。
try:
如
異常和狀態管理2
起點 檢查 導致 有用 eth 調用 指令 class trace System.Excelption 類型提供的制度 StackTrace 屬性。
catch 塊可讀取該屬性來獲取一個堆棧跟蹤,它描述了異常發生前調用了哪些方法。檢查異常原因並改正代碼時,這些信息很有用。訪
免費的上網行為管理系統和軟路由系統推薦。
上網行為管理 網絡安全網關路由系統、又稱RouterOS,已經是一個非常開源的技術了。不管是在LINUX系統上的,還是在windows系統上的,都很很多這樣的開源項目,技術簡單,結構也非常單一。而隨著時代發展,後期又加上了VPN和基礎的包過濾防火墻,也都是開源成熟的項目。大部分廠家也是在這些項目上修修改改,包
Linux用戶和組管理
組 用戶 passwd useradd shadow groupadd 一、linux用戶和組管理1.用戶、組和權限管理 每個使用者:用戶 每個使用者: 用戶標識、密碼 認證Authentication:身份識別 授權Authority:對應相應的權限 審計Account
Linux 程序設計學習筆記----Linux下文件類型和屬性管理
腳本 types.h 沒有 oot 創建 jsb 文件 屬性 文件大小
轉載請註明出處:http://blog.csdn.net/suool/article/details/38318225
部分內容整理自網絡,在此感謝各位大神。
Linux文件類型和權限
數據表示
RPM包管理-yum在線管理-IP地址配置和網絡yum源
roo 使用 bsp 分享 9.png ip地址 配置 ima png [[email protected]/* */~]#setup
#使用setup工具
1、選擇網絡配置
2、設備設置
3、選擇第一塊網卡、按回車進入設置
4、取消“*”號、設置內容為下
sql server 性能優化和日常管理維護 筆記
sel .text reads where 導入 語句 data offset file 1.將sqlserver Profile收集到的trace 比如 duration >5000ms 的trace 文件 導入到sample 表分析或者用查詢優化器顧問分析
sqlserver表和庫管理
sqlserver1.1. ql server 2008R2如何存儲數據數據庫在磁盤上是以文件為單位存儲的,由數據文件和事物日誌文件組成。一個數據庫至少應該包含一個數據文件和一個事物日誌文件。數據庫創建在物理介質(磁盤)上的一個或多個文件上,它預先分配了被數據和事物日誌所要適用的物理存儲空間。存儲數據的文件叫
爬蟲學習——URL管理器和實現方法
可選 架構 緩存 sql 元素 技術分享 字段 結構 想要 url管理器一共有三種實現方法,作為個人,我們應當選擇哪種實現方法呢?答案就在下面
爬蟲的簡單架構
一、URL管理器
實現方式:有三種
1.內存中
python中set()可以直接去除重復的元素
2.關系數據
Objective-C 內存管理retain和release
計數 nco 優雅 tracking con void sep res 釋放資源
OC使用引用計數來管理內存,每個繼承NSObject的對象,內部都維護了一個引用計數器retainCount。當對象創建時(調用alloc或者new)引用計數器會+1, 手動調用retai
使用git和github管理項目代碼
你是 -s 同時 查看 現在 後來 為我 一次 官方 以前不知道使用代碼管理工具,最後寫的一些東西都沒有了,由於硬盤壞了或者不小心格式化了之類的,後來使用了Git
和Github來托管自己的代碼和讀書筆記方便了不少,到哪裏只要有網就可以把自己的東西拷貝下來繼續使用。
我這裏
JVM內存管理機制和垃圾回收機制
mark 代碼 本地方法棧 final類 boot 存取 帶來 logs byte JVM自身結構物理圖:
Java代碼編譯和執行的整個過程包含了以下三個重要的機制:
1.java源碼編譯機制
1)分析和輸入到符號表
class文件結構包含:
結構