博主最近在开发导师的一个项目,写了一个动态生成控件的组件,这个组件的基本功能是在一个父控件中生成若干个子控件,这些控件有拖动事件或者点击事件,原本在生成子控件个数较小时,没有什么问题,但如果子控件个数较多,页面就出现了卡顿。因为父控件是放在一个fragment中,这导致viewPager滑动切换页面时,不论是从本页面滑出还是滑入本页面,都会卡顿。同时子控件的拖动也会掉帧。
问题分析:
原以为是子控件个数较多导致了整个页面的卡顿,但博主在布局文件中预先布置多个子控件,页面竟不会卡顿。那么问题一定是出在了别的地方。使用Profiler查看了项目的性能分析结果,发现内存占用的大头是Graphics这一项,也就是页面的图形渲染,占到32M左右。
查阅资料之后,发现是因为在java代码中使用了setbackgroundrResource()这个函数导致的,所有子控件的background都是在java代码中设置的,这就导致了项目的OOM。
下面是动态生成子控件的代码:
TextView textView = new TextView(mContext);
mRelativeLayout.addView(textView);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) textView.getLayoutParams();
layoutParams.height = (int) ((btn_row / FARM_ROW) * (farmHeight - 20));
layoutParams.width = (int) ((btn_column / FARM_COLUMN) * (farmWidth - 20));
layoutParams.topMargin = (int) (btn_y * farmHeight);
layoutParams.leftMargin = (int) (btn_x * farmWidth);
textView.setLayoutParams(layoutParams);
textView.setText(mJsonList.get(i).getString("name"));
textView.setTextColor(mContext.getResources().getColor(R.color.color_white));
textView.setBackgroundResource(R.drawable.bg_field);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
textView.setAutoSizeTextTypeUniformWithConfiguration(5, 13, 2, TypedValue.COMPLEX_UNIT_SP);
} else {
textView.setTextSize(9);
}
textView.setEms(1);
textView.setGravity(Gravity.CENTER);
textView.setTag(i);
if (action == DRAG_EVENT) {
textView.setOnTouchListener(moveTouchListenr);
} else if (action == CLICK_EVENT) {
textView.setOnClickListener(onClickListener);
}
问题解决:
既然在java代码中使用setBackgroundResource会导致OOM,但还是想要给子控件设置background,所以我利用inflate,加载一个在布局文件中已经写好的子控件布局,这样就避免了使用setbackgroundrResource()。
代码修改后博主又分析了项目的性能,发现Graphics这一项比之前减少了3M左右,降低到了29M。虽然仅仅是3M内存的右优化,但界面已经不在卡顿
下面是修改后的代码
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.field_view, null, false);
TextView textView = view.findViewById(R.id.field_name);
textView.setText(mJsonList.get(i).getString("name"));
mRelativeLayout.addView(view);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.height = (int) ((btn_row / FARM_ROW) * (farmHeight - 20));
layoutParams.width = (int) ((btn_column / FARM_COLUMN) * (farmWidth - 20));
layoutParams.topMargin = (int) (btn_y * farmHeight);
layoutParams.leftMargin = (int) (btn_x * farmWidth);
view.setLayoutParams(layoutParams);
view.setTag(i);
if (action == DRAG_EVENT) {
view.setOnTouchListener(moveTouchListenr);
} else if (action == CLICK_EVENT) {
view.setOnClickListener(onClickListener);
}
结论:
动态生成控件时,尽量避免使用setBackground()、setBackgroundResource()、setBackGroundDrawable()等一系列函数,view.getBackground()同样也会导致OOM,也要避免在java代码中过多使用,包括ImageView.setImageResource()等一系列函数也存在OOM的问题。
网友评论