1️⃣、getDimension() vs ``getDimensionPixelSize()
vs getDimensionPixelOffset()
在 Android 开发中,getDimension()
、getDimensionPixelSize()
和 getDimensionPixelOffset()
都是 Resources
类中用于获取尺寸资源的方法,主要用于将 dp
、sp
等单位转换为像素(px),但它们的返回值和用途有所不同:
getDimension(int id)
- 返回值 :
float
类型,返回转换后的像素值(包含小数部分)。 - 转换逻辑 :根据当前设备的屏幕密度,将资源中定义的
dp
/sp
等单位转换为精确的像素值(可能带有小数)。 - 适用场景:需要精确像素值(如动画中的细微位置计算、绘制自定义 View 时的坐标定位等)。
java
// 示例:获取 res/values/dimens.xml 中定义的尺寸
float dimension = getResources().getDimension(R.dimen.margin);
getDimensionPixelSize(int id)
- 返回值 :
int
类型,返回转换后四舍五入的像素值(整数)。 - 转换逻辑 :先执行与
getDimension()
相同的转换,得到float
像素值,再通过四舍五入(Math.round()
)取整。 - 适用场景 :大多数 UI 布局场景(如设置 View 的宽高、边距等),因为 View 的尺寸属性(
layout_width
等)只接受整数像素。
java
int pixelSize = getResources().getDimensionPixelSize(R.dimen.button_height);
view.setHeight(pixelSize); // View 高度需整数像素
getDimensionPixelOffset(int id)
-
返回值 :
int
类型,返回转换后截断小数的像素值(整数,相当于(int)floatValue
)。 -
转换逻辑 :先执行与
getDimension()
相同的转换,得到float
像素值,再直接截断小数部分(取整数部分,不四舍五入)。 -
适用场景:需要严格向下取整的场景(如避免因四舍五入导致的布局溢出)。
int pixelOffset = getResources().getDimensionPixelOffset(R.dimen.padding);
view.setPadding(pixelOffset, 0, 0, 0);
对比总结
方法 | 返回类型 | 转换方式 | 典型用途 |
---|---|---|---|
getDimension() |
float |
精确转换(保留小数) | 动画、绘制等需要高精度的场景 |
getDimensionPixelSize() |
int |
四舍五入取整 | 大多数 UI 布局(宽高、边距等) |
getDimensionPixelOffset() |
int |
截断小数取整 | 需严格向下取整的布局场景 |
注意事项
- 这三个方法的输入都是尺寸资源 ID(定义在
res/values/dimens.xml
中,单位可以是dp
、sp
、px
等)。 - 对于
px
单位的资源,三者返回值一致(因为无需转换,直接返回整数或浮点形式的像素值)。 - 推荐优先使用
getDimensionPixelSize()
处理 UI 布局,它的四舍五入逻辑更符合人眼对尺寸的感知。
在 Android 开发中,除了 getDimension()
、getDimensionPixelSize()
和 getDimensionPixelOffset()
,还有其他获取尺寸资源的方法,适用于不同场景
getFraction()
-
功能:获取资源中定义的分数值,可根据参考尺寸计算实际像素。
-
适用场景:需按比例计算尺寸时,比如根据父容器大小设置子 View 尺寸。
-
使用示例 :
xml
XML<!-- 在 res/values/dimens.xml 中定义 --> <fraction name="half_width">50%p</fraction> <!-- 相对于父容器的50% -->
使用
java// 参数:资源ID、基准宽度、基准高度(单位px),返回计算后的float值 float halfWidth = getResources().getFraction(R.fraction.half_width, parentWidth, parentHeight);
getInteger()
-
功能:获取资源中定义的整数类型尺寸或数值。
-
适用场景:获取整数配置,如网格列数、最大显示数量等。
-
使用示例 :
xml
XML<!-- 在 res/values/integers.xml 中定义 --> <integer name="grid_columns">3</integer>
使用
javaint columns = getResources().getInteger(R.integer.grid_columns);
getDimensionForSize()
(API 29+)
-
功能 :专为获取 View 尺寸设计,返回值为
int
,效果类似getDimensionPixelSize()
。 -
特点:在 API 29 及以上版本中,推荐用于 View 尺寸设置,更符合布局场景。
-
使用示例 :
javaif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { int size = getResources().getDimensionForSize(R.dimen.view_size); view.setLayoutParams(new ViewGroup.LayoutParams(size, size)); }
TypedValue
配合resolveDimension()
-
功能:手动解析尺寸资源,获取原始值和单位,适合需要自定义转换逻辑的场景。
-
使用示例 :
javaTypedValue typedValue = new TypedValue(); getResources().getValue(R.dimen.margin, typedValue, true); // 获取原始值和单位(如 typedValue.data 为值,typedValue.unit 为单位) float value = typedValue.getDimension(getResources().getDisplayMetrics());
- 直接从
TypedArray
中获取
-
功能 :在自定义 View 的
obtainStyledAttributes()
中获取布局文件中定义的尺寸属性。 -
适用场景:自定义 View 解析自定义属性时使用。
-
使用示例 :
javaTypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView); // 类似 getDimensionPixelSize() int customSize = ta.getDimensionPixelSize(R.styleable.MyCustomView_customSize, 0); ta.recycle();
总结
这些方法适用场景各有不同:
- 比例计算用
getFraction()
; - 整数配置用
getInteger()
; - 高版本 View 尺寸设置用
getDimensionForSize()
; - 自定义解析逻辑用
TypedValue
; - 自定义 View 属性解析用
TypedArray
相关方法。
2️⃣、View 测量与布局相关的临近方法
这些方法用于 View 的尺寸计算和位置确定,常配套使用:
方法 | 功能 | 关联方法 | 区别与联系 |
---|---|---|---|
measure(int widthMeasureSpec, int heightMeasureSpec) |
测量 View 所需尺寸 | getMeasuredWidth() getMeasuredHeight() |
measure() 触发测量,后两者获取测量结果(测量尺寸) |
layout(int l, int t, int r, int b) |
确定 View 在父容器中的位置 | getLeft() /getTop() getRight() /getBottom() |
layout() 确定位置,后四者获取相对父容器的坐标 |
onMeasure(int, int) onLayout(boolean, int, int, int, int) |
自定义 View 时重写的测量和布局逻辑 | setMeasuredDimension() |
前者需调用 setMeasuredDimension() 保存测量结果,后者用于子 View 布局 |
getWidth() getHeight() |
获取 View 最终显示的宽高 | getMeasuredWidth() getMeasuredHeight() |
前者是布局后实际尺寸,后者是测量尺寸,多数情况相等,但存在测量≠布局的场景(如父容器强制限制) |
3️⃣、资源获取相关的临近方法
用于获取各类资源,因返回值或用途不同而区分:
方法 | 功能 | 关联方法 | 区别与联系 |
---|---|---|---|
getResources().getString(int id) |
获取字符串资源 | getString(int id, Object... formatArgs) |
后者支持格式化(如 %s 占位符替换) |
getDrawable(int id) |
获取 Drawable 资源 | getDrawable(int id, Theme theme) |
后者可指定主题(API 21+),适配不同主题下的资源 |
getColor(int id) |
获取颜色值 | getColor(int id, Theme theme) |
类似 Drawable,后者支持主题(API 23+) |
getDimension(...) 系列 |
获取尺寸资源(见前文) | getFraction(...) getInteger(...) |
同属资源获取,但处理不同类型(尺寸、分数、整数) |
4️⃣、Intent 跳转相关的临近方法
用于 Activity 跳转和数据传递,功能互补:
方法 | 功能 | 关联方法 | 区别与联系 |
---|---|---|---|
startActivity(Intent) |
启动新 Activity | startActivityForResult(Intent, int) |
后者期望从新 Activity 获取返回数据(已被 Activity Result API 替代) |
startService(Intent) |
启动服务 | bindService(Intent, ServiceConnection, int) |
前者启动独立服务,后者绑定服务并获取交互接口 |
putExtra(String, ...) |
向 Intent 中添加数据 | getExtra(String) |
前者存数据,后者取数据,配套用于组件间通信 |
5️⃣、SharedPreferences 操作相关的临近方法
用于轻量级数据存储,读写逻辑对应:
方法 | 功能 | 关联方法 | 区别与联系 |
---|---|---|---|
edit() |
获取编辑器对象 | commit() apply() |
edit() 开启编辑,后两者提交修改(commit() 同步返回结果,apply() 异步高效) |
getString(String, String) |
获取 String 类型数据 | putString(String, String) |
读写对应,其他类型(int /boolean 等)也有类似成对方法 |
6️⃣、线程与 Handler 相关的临近方法
用于线程间通信,控制任务执行时机:
方法 | 功能 | 关联方法 | 区别与联系 |
---|---|---|---|
post(Runnable) |
向 Handler 所在线程(通常主线程)提交任务 | postDelayed(Runnable, long) |
后者延迟执行任务,均用于切换到主线程更新 UI |
sendMessage(Message) |
发送消息到消息队列 | handleMessage(Message) |
前者发消息,后者在 Handler 中处理消息,是消息机制的核心配对方法 |
runOnUiThread(Runnable) |
在主线程执行任务 | post(Runnable) (Handler) |
两者功能类似,runOnUiThread 是 Activity 的便捷方法,内部依赖 Handler |
分析临近方法的意义
- 避免误用 :例如区分
getMeasuredWidth()
和getWidth()
,避免在onMeasure()
中使用getWidth()
(此时布局未完成,值为 0)。 - 理解设计逻辑 :如
commit()
和apply()
的区别,体现了 Android 对性能(异步)和可靠性(同步返回结果)的平衡。 - 优化代码 :例如用
apply()
替代commit()
提升 SharedPreferences 写入性能,用Activity Result API
替代过时的startActivityForResult()
。
7️⃣、startActivityForResult()
vs Activity Result API
功能 :均用于从启动的 Activity 获取返回数据
区别:
维度 | startActivityForResult() (已过时) |
Activity Result API (推荐) |
---|---|---|
用法 | 重写 onActivityResult() 处理返回数据 |
注册 ActivityResultCallback 回调 |
生命周期关联 | 依赖 Activity 生命周期,易因配置变化丢失数据 | 与生命周期解耦,自动处理配置变化 |
类型安全 | 需手动解析数据,易出错 | 支持泛型,编译期检查类型 |
示例代码 | startActivityForResult(intent, REQUEST_CODE); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { ... } |
ActivityResultLauncher launcher = registerForActivityResult(...); launcher.launch(intent);<br> |
8️⃣、commit()
vs apply()
(SharedPreferences)
功能 :提交 SharedPreferences 的编辑内容
区别:
维度 | commit() |
apply() (推荐) |
---|---|---|
执行方式 | 同步执行,阻塞当前线程 | 异步执行,提交到主线程队列 |
返回值 | boolean ,表示提交是否成功 |
无返回值 |
适用场景 | 需要知道提交结果的场景(极少) | 大多数场景,性能更优 |
注意事项 | 主线程调用可能导致 ANR | 不会阻塞线程,但数据未持久化时进程被杀会丢失 |
9️⃣、getWidth()
vs getMeasuredWidth()
功能 :获取 View 的宽度
区别:
维度 | getWidth() |
getMeasuredWidth() |
---|---|---|
时机 | 布局(layout() )完成后有效 |
测量(measure() )完成后有效 |
数值来源 | 实际显示宽度(right - left ) |
测量得出的宽度(setMeasuredDimension() 设置) |
典型场景 | 布局完成后获取最终尺寸 | 自定义 View 测量阶段获取测量结果 |
特殊情况 | 可能被父容器强制修改(如超出父布局) | 反映 View 自身期望的尺寸 |
🔟、invalidate()
vs postInvalidate()
功能 :触发 View 重绘
区别:
维度 | invalidate() |
postInvalidate() |
---|---|---|
调用线程 | 必须在主线程调用 | 可在子线程调用 |
实现原理 | 直接触发重绘流程 | 内部通过 Handler 切换到主线程调用 invalidate() |
适用场景 | 主线程中更新 UI 后重绘 | 子线程中计算数据后触发重绘 |
🔟1️⃣、dp
vs sp
vs px
功能 :定义尺寸单位
区别:
维度 | dp (density-independent pixel) |
sp (scale-independent pixel) |
px (pixel) |
---|---|---|---|
适配性 | 随屏幕密度变化,保证不同设备显示比例一致 | 除屏幕密度外,还受系统字体大小影响 | 固定像素,不适配 |
适用场景 | 布局尺寸(宽高、边距等) | 文字大小 | 极少使用(如精确像素绘制) |
🔟2️⃣、View.setVisibility(View.GONE)
vs View.setVisibility(View.INVISIBLE)
功能 :控制 View 的可见性
区别:
维度 | GONE |
INVISIBLE |
---|---|---|
空间占用 | 不占用布局空间,相当于从布局中移除 | 占用空间,但完全透明 |
测量与布局 | 不参与测量和布局流程 | 参与测量和布局,只是不绘制 |
适用场景 | 临时隐藏且需释放空间 | 临时隐藏但保持布局结构 |
🔟3️⃣、getString()
vs getText()
功能 :获取字符串资源
区别:
维度 | getString(int resId) |
getText(int resId) |
---|---|---|
返回类型 | String |
CharSequence |
支持资源类型 | 纯文本字符串 | 支持带样式的字符串(如 <b> 标签) |
示例 | getString(R.string.app_name) |
getText(R.string.styled_text) |
总结
相似方法的核心区别通常体现在:
- 线程安全性 (如
invalidate()
主线程 vspostInvalidate()
子线程) - 生命周期关联(如旧版启动 vs Activity Result API)
- 性能与副作用 (如
commit()
同步 vsapply()
异步) - 适用场景 (如
dp
用于布局 vssp
用于文字)
使用时需根据具体场景(线程、生命周期、性能需求等)选择,优先使用官方推荐的新 API(如 Activity Result API 替代 startActivityForResult()
)。
🔟4️⃣、其他
案例 1:finish()
vs onBackPressed()
(Activity 关闭相关)
相似点 :都可用于关闭当前 Activity
差异分析:
-
finish()
:直接触发 Activity 销毁流程,调用后 Activity 进入onDestroy()
生命周期,适合在代码逻辑中主动关闭页面(如点击 "完成" 按钮)。java// 点击按钮关闭页面 btnFinish.setOnClickListener(v -> finish());
-
onBackPressed()
:是系统回调方法,当用户按下物理返回键或导航栏返回按钮时触发。默认实现是调用finish()
,但可重写以添加额外逻辑(如双击返回退出、弹窗确认)。java@Override public void onBackPressed() { // 自定义逻辑:如果是首页,双击返回退出 if (isHomePage && System.currentTimeMillis() - lastBackTime < 2000) { super.onBackPressed(); // 调用父类实现(即 finish()) } else { Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show(); lastBackTime = System.currentTimeMillis(); } }
选择依据 :主动关闭用 finish()
;拦截返回键行为用 onBackPressed()
。
案例 2:setVisibility(View.GONE)
vs removeView()
(View 移除相关)
相似点 :都可让 View 从界面消失
差异分析:
-
setVisibility(View.GONE)
:View 仍存在于布局结构中,只是不显示且不占用空间,可通过setVisibility(View.VISIBLE)
恢复显示,适合临时隐藏(如切换列表筛选状态)。java// 筛选条件不满足时隐藏按钮 btnFilter.setVisibility(filterCondition ? View.VISIBLE : View.GONE);
-
removeView()
:将 View 从父容器中彻底移除,若需再次显示需重新调用addView()
添加,适合确定不再使用的场景(如动态表单删除某一行)。java// 从父布局中移除不需要的输入项 parentLayout.removeView(extraInputView);
选择依据 :临时隐藏且可能恢复用 GONE
;永久移除用 removeView()
。
案例 3:notifyDataSetChanged()
vs notifyItemChanged(int)
(RecyclerView 刷新相关)
相似点 :都用于刷新 RecyclerView 列表
差异分析:
-
notifyDataSetChanged()
:通知列表 "所有数据已变",会触发整个列表重新绑定和绘制,效率低,适合数据批量替换或结构变化(如切换数据源)。java// 整体数据替换时使用 mList = newData; adapter.notifyDataSetChanged();
-
notifyItemChanged(int position)
:仅通知指定位置的数据变化,只会重新绑定该位置的 Item,效率高,适合单个数据更新(如点赞状态变化)。java// 仅更新第5项数据 mList.get(5).setLiked(true); adapter.notifyItemChanged(5);
选择依据 :局部更新用 notifyItemXXX
系列方法;全量刷新才用 notifyDataSetChanged()
。
案例 4:postDelayed(Runnable, long)
vs Handler.postDelayed(Runnable, long)
(延迟任务相关)
相似点 :都可实现延迟执行任务
差异分析:
-
View.postDelayed(Runnable, long)
:任务在 View 所在的线程(通常是主线程)执行,且会检查 View 是否已被销毁(mAttachInfo != null
),避免内存泄漏,适合与 View 相关的延迟操作(如延迟隐藏提示框)。java// 延迟3秒隐藏提示框 tipView.postDelayed(() -> tipView.setVisibility(View.GONE), 3000);
-
Handler.postDelayed(Runnable, long)
:需要手动管理 Handler 的生命周期,若 Handler 持有 Activity 引用且未及时移除任务,可能导致内存泄漏,适合全局延迟任务(如定时轮询)。java// 需在 Activity 销毁时调用 handler.removeCallbacksAndMessages(null) Handler handler = new Handler(Looper.getMainLooper()); handler.postDelayed(() -> doPolling(), 5000);
选择依据 :与 View 相关的延迟任务用 View.postDelayed()
;全局任务用 Handler
并注意及时取消。
案例 5:getStringArray()
vs getResources().obtainTypedArray()
(数组资源获取相关)
相似点 :都用于获取资源文件中定义的数组
差异分析:
-
getStringArray(int resId)
:直接获取字符串数组,适合简单的字符串数组(如string-array
定义的列表项)。XML<!-- res/values/arrays.xml --> <string-array name="city_list"> <item>北京</item> <item>上海</item> </string-array>
使用
javaString[] cities = getResources().getStringArray(R.array.city_list);
-
obtainTypedArray(int resId)
:获取typed-array
资源,支持多种类型(字符串、图片、尺寸等),适合复杂数组(如图文混排的列表)。XML<!-- res/values/arrays.xml --> <typed-array name="icon_text_array"> <item>@drawable/ic_home</item> <item>首页</item> <item>@drawable/ic_profile</item> <item>我的</item> </typed-array>
运行
javaTypedArray ta = getResources().obtainTypedArray(R.array.icon_text_array); Drawable homeIcon = ta.getDrawable(0); String homeText = ta.getString(1); ta.recycle(); // 必须回收,避免内存泄漏
选择依据 :纯字符串数组用 getStringArray()
;多类型数组用 typed-array
配合 obtainTypedArray()
。