Cân nhắc về hiệu suất
Khi phát triển các thành phần giao diện tùy chỉnh, hiệu suất là một yếu tố then chốt cần được chú ý. Dưới đây là một số đề xuất và phương pháp tốt để cải thiện hiệu suất:
- Tránh phân bổ đối tượng bên trong phương thức
onDraw(). - Tối ưu hóa các phép tính và giảm thiểu việc vẽ quá mức.
- Sử dụng cấu trúc dữ liệu hiệu quả để lưu trữ thông tin tạm thời.
Ví dụ về phân bổ đối tượng không cần thiết
Dưới đây là một ví dụ minh họa về cách phân bổ đối tượng không cần thiết có thể ảnh hưởng đến hiệu suất:
public class PerformanceExample extends View {
private float angle;
public PerformanceExample(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
this.angle = 0.f;
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Rect rect = new Rect(0, 0, getWidth(), getHeight());
Paint paint = new Paint();
paint.setColor(0xff000000);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(rect, paint);
canvas.save();
canvas.rotate(angle, getWidth() / 2, getHeight() / 2);
canvas.translate((getWidth() - getWidth() / 4) / 2, (getHeight() - getHeight() / 4) / 2);
rect = new Rect(0, 0, getWidth() / 4, getHeight() / 4);
paint.setColor(0xffffffff);
canvas.drawBitmap(bitmap, 0, 0, paint);
canvas.drawRect(rect, paint);
canvas.restore();
invalidate();
bitmap.recycle();
angle += 0.1f;
}
}
Khi chạy đoạn mã này, bạn sẽ thấy rằng nó tạo ra một hình chữ nhật quay tròn nhưng cũng gây ra nhiều rác bộ nhớ do liên tục tạo mới đối tượng.
Tối ưu hóa mã nguồn
Bên cạnh việc tránh phân bổ đối tượng không cần thiết, chúng ta cũng có thể áp dụng các kỹ thuật tối ưu hóa khác như sau:
- Sử dụng phép toán cố định thay vì số thực để tăng tốc độ xử lý.
- Giảm thiểu số lần gọi lại phương thức
invalidate(). - Lưu trữ trước các giá trị đã tính toán để tránh tính toán lặp đi lặp lại.
Ví dụ về chuyển đổi YUV sang RGB
Một ví dụ cụ thể về tối ưu hóa là chuyển đổi từ định dạng YUV sang RGB. Ban đầu, chúng ta có thể sử dụng các phép toán số thực:
private static void yuvToRgb(int width, int height, byte[] yuvData, int[] rgbData) {
int uvOffset = width * height;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Code conversion here...
}
}
}
Tuy nhiên, bằng cách chuyển sang phép toán cố định và lưu trữ các bảng tra cứu trước, chúng ta có thể cải thiện hiệu suất đáng kể:
private static final int[] LUMINANCE_TABLE = precomputeLuminance();
private static final int[] CHROMA_R_TABLE = precomputeChromaR();
private static final int[] CLIP_VALUES_R = precomputeClipValuesR();
private static void yuvToRgbOptimized(int width, int height, byte[] yuvData, int[] rgbData) {
int uvOffset = width * height;
int offset = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j += 2) {
// Use lookup tables to speed up conversion...
}
}
}
Kết luận
Bài viết này đã cung cấp cái nhìn tổng quan về cách xây dựng và tối ưu hóa các thành phần giao diện tùy chỉnh trên Android. Việc tuân thủ các nguyên tắc hiệu suất và áp dụng các kỹ thuật tối ưu hóa sẽ giúp cải thiện đáng kể trải nghiệm người dùng.