type
status
date
slug
summary
tags
category
icon
password

设置页的处理逻辑

packages/apps/Settings/src/com/android/settings/development/ShowLayoutBoundsPreferenceController.java中有:
public class ShowLayoutBoundsPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { private static final String DEBUG_LAYOUT_KEY = "debug_layout"; public ShowLayoutBoundsPreferenceController(Context context) { super(context); } @Override public String getPreferenceKey() { return DEBUG_LAYOUT_KEY; } // 当用户切换选项的时候,通过IBinder通知到各种服务 @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final boolean isEnabled = (Boolean) newValue; DisplayProperties.debug_layout(isEnabled); SystemPropPoker.getInstance().poke(); return true; } @Override public void updateState(Preference preference) { final boolean isEnabled = DisplayProperties.debug_layout().orElse(false); ((SwitchPreference) mPreference).setChecked(isEnabled); } @Override protected void onDeveloperOptionsSwitchDisabled() { super.onDeveloperOptionsSwitchDisabled(); DisplayProperties.debug_layout(false); ((SwitchPreference) mPreference).setChecked(false); } }
DisplayProperties是生成的类,看一下其中的debug_layout属性:
public static void debug_layout(Boolean value) { SystemProperties.set("debug.layout", value == null ? "" : value.toString()); }
Android系统属性定义在.sysprop文件中,其本质上是一个protobuf文件.
看一下debug_layout属性(system/libsysprop/srcs/android/sysprop/DisplayProperties.sysprop中):
prop { api_name: "debug_layout" type: Boolean scope: Internal access: ReadWrite prop_name: "debug.layout" }
然后系统会自动生成一些中间类.比如上面的DisplayProperties.java.
总结一下,其实就是:
  1. 系统属性定义在.sysprop文件中,系统会自动生成一些中间类用于读写属性
  1. 设置页中用户打开/关闭开关,会改变属性值,然后通过Binder机制通知给各个服务;

debug.layout运行机制

在ViewRootImpl初始化的时候会执行下面的方法:
public void loadSystemProperties() { mHandler.post(new Runnable() { @Override public void run() { // ... // Layout debugging boolean layout = DisplayProperties.debug_layout().orElse(false); if (layout != mAttachInfo.mDebugLayout) { mAttachInfo.mDebugLayout = layout; if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); } } } }); } // 自身以及其子View全部都重新绘制 void invalidateWorld(View view) { view.invalidate(); if (view instanceof ViewGroup) { ViewGroup parent = (ViewGroup) view; for (int i = 0; i < parent.getChildCount(); i++) { invalidateWorld(parent.getChildAt(i)); } } }
在View的draw中有下面这一句:
if (isShowingLayoutBounds()) { debugDrawFocus(canvas); } final private void debugDrawFocus(Canvas canvas) { if (isFocused()) { final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); final int l = mScrollX; final int r = l + mRight - mLeft; final int t = mScrollY; final int b = t + mBottom - mTop; final Paint paint = getDebugPaint(); paint.setColor(DEBUG_CORNERS_COLOR); // Draw squares in corners. paint.setStyle(Paint.Style.FILL); // 左 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); // 右 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); // 下 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); // 上 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); // 绘制一个View上的大X paint.setStyle(Paint.Style.STROKE); canvas.drawLine(l, t, r, b, paint); canvas.drawLine(l, b, r, t, paint); } }
上面这些就是我们看到的那些红色框框的绘制逻辑了.

adb获取系统属性

  • 获取全部属性
    • adb shell getprop
  • 获取指定属性
    • adb shell getprop debug.layout

adb打开关闭“显示布局边界”

adb shell setprop debug.layout true adb shell setprop debug.layout false
执行完命令之后要重启APP才会看到效果.
Activity启动流程分析使用VSCode阅读Android源码
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏