面试题答案
一键面试- 优化布局
- 减少布局嵌套:
- 原理:布局嵌套过多会导致系统在测量、布局和绘制时花费更多时间和资源,增加过度绘制的可能性。例如,原本使用多层LinearLayout嵌套来实现界面,可尝试使用ConstraintLayout等更灵活且嵌套层级少的布局方式。
- 示例:假设原本有一个界面,使用了三层LinearLayout嵌套来排列一些TextView和ImageView。
改为ConstraintLayout后:<!-- 原始多层嵌套布局 --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="标题"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="内容1"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="内容2"/> </LinearLayout> </LinearLayout>
<!-- 使用ConstraintLayout优化后的布局 --> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/title_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="标题" android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> <ImageView android:id="@+id/icon_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon" app:layout_constraintStart_toEndOf="@id/title_text" app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="8dp" android:layout_marginTop="8dp"/> <TextView android:id="@+id/content1_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="内容1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/title_text" android:layout_marginStart="8dp" android:layout_marginTop="8dp"/> <TextView android:id="@+id/content2_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="内容2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/content1_text" android:layout_marginStart="8dp" android:layout_marginTop="8dp"/> </androidx.constraintlayout.widget.ConstraintLayout>
- 使用ViewStub:
- 原理:ViewStub是一个轻量级的View,在初始时不占用布局空间,只有在调用
inflate()
方法时才会将其指定的布局加载到界面中。这对于一些在特定条件下才需要显示的布局非常有用,可以避免一开始就绘制不必要的视图,从而减少过度绘制。 - 示例:假设在自定义View中有一个隐藏的提示布局,只有在用户点击某个按钮时才显示。
- 首先在布局文件中定义ViewStub:
<ViewStub android:id="@+id/hint_view_stub" android:layout_width="match_parent" android:layout_height="wrap_content" android:inflatedId="@+id/hint_view" android:layout="@layout/hint_layout"/>
- 然后在代码中,当用户点击按钮时加载ViewStub:
class CustomView : View { private lateinit var hintViewStub: ViewStub constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) init { hintViewStub = findViewById(R.id.hint_view_stub) val button = Button(context) button.text = "显示提示" button.setOnClickListener { if (!hintViewStub.isInflated) { hintViewStub.inflate() } } addView(button) } }
- 原理:ViewStub是一个轻量级的View,在初始时不占用布局空间,只有在调用
- 减少布局嵌套:
- 优化绘制顺序
- 合理设置View的visibility:
- 原理:如果一个View不可见(
View.GONE
),系统不会对其进行绘制,这样可以避免不必要的绘制操作,减少过度绘制。 - 示例:假设自定义View中有一个状态指示View,在某些状态下不需要显示。
class CustomView : View { private lateinit var statusIndicator: View constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) init { statusIndicator = View(context) // 设置初始不可见 statusIndicator.visibility = View.GONE addView(statusIndicator) } fun updateStatus(isVisible: Boolean) { if (isVisible) { statusIndicator.visibility = View.VISIBLE } else { statusIndicator.visibility = View.GONE } } }
- 原理:如果一个View不可见(
- 使用Canvas的裁剪功能:
- 原理:通过
Canvas
的clipRect()
等裁剪方法,可以限制绘制区域,只在指定区域内进行绘制,避免在不需要的区域绘制,从而减少过度绘制。 - 示例:假设要在自定义View中绘制一个圆形进度条,只在圆形区域内绘制进度。
class CircularProgressView : View { private val paint = Paint() private var progress = 0f constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val centerX = width / 2f val centerY = height / 2f val radius = min(width, height) / 2f - 10 // 裁剪出圆形区域 val path = Path() path.addCircle(centerX, centerY, radius, Path.Direction.CW) canvas.clipPath(path) // 绘制进度条 paint.color = Color.BLUE canvas.drawArc( RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius), -90f, progress * 360f, true, paint ) } fun setProgress(progress: Float) { this.progress = progress invalidate() } }
- 原理:通过
- 合理设置View的visibility: