Android ListView optimization to improve android application efficiency

  • 2020-11-20 06:16:01
  • OfStack

ListView is a frequently used control, and each subitem in ListView can be either a string or a composite control. Adapter is the middleman between listview and the data source.

When each piece of data enters the visible area, getview () of adapter is called, returning a view that represents the specific data. When touching the scroll, call frequently. Supports hundreds of thousands of pieces of data.

Here is the xml file showing each piece of data:


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal">
<ImageView android:id="@+id/icon"
android:layout_width="48dip"
android:layout_height="48dip" />
<TextView android:id="@+id/text"
android:layout_gravity="center_vertical"
android:layout_width="0dip"
android:layout_weight="1.0"
android:layout_height="wrap_content" />
</LinearLayout>

1. The easiest way, the slowest and the least practical


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}

2. Using convertview to recycle view, the efficiency is increased by 200%.


public View getView(int pos, View convertView,
ViewGroup parent){
if (convertView == null) {
convertView = mInflater.inflate(
R.layout.list_item, null);
}
((TextView) convertView.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) convertView.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}

3. Using the viewholder model, the efficiency was increased by 50%


static class ViewHolder {
TextView text;
ImageView icon;
}
public View getView(int pos, View convertView, ViewGroup parent){
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(
R.id.text));
holder.icon = (ImageView) convertView.findViewButId(
R.id.icon));
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA[pos]);
holder.icon.setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}

Comparison of adapter update efficiency:

1 was updated less than 10 frames/second

Update 2 is closer to 30 frames/second

Update 3 is closer to 40 frames/second

Background and image

The view background image always fills the entire view area

1. Improper image size will result in automatic scaling

2. Avoid real-time scaling

3. It is best to pre-scale to the view size


originalImage = Bitmap.createScaledBitmap(
originalImage, // 􂿕 Scale the image 
view.getWidth(), //  View width 
view.getHeight(), //  Height of the view 
true); // 􀽮 Linear filter 

The efficiency of 1 is close to 25 frames/second

The efficiency of 2 is close to 50 frames/second

By default, the window has an opaque background

Sometimes you don't

- the & # 1055601; The & # 1063383; The highest level view is opaque

- the & # 1055601; The highest level view covers the entire window


layout_width = fill_parent
layout_height = fill_parent

Updating an invisible background is a waste of time

Delete window background:

1. Modify the code


public void onCreate(Bundle icicle){
super.onCreate(icicle);
setContentView(R.layout.mainview);
//  Delete window background 
getWindow().setBackgroundDrawable(null);
...
 } 

2. Modify xml

First determine your res/values/styles xml there


<resources>
<style name="NoBackgroundTheme" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
</resources>

Then edit ES103en.xml


<activity android:name="MyApplication"
android:theme="@style/NoBackgroundTheme">
...
</activity>

Update request

Calling the invalidate () method when the screen needs to be updated is simple and convenient, but it's too expensive to update the entire view.

It's best to find an invalid area and then call


invalidate(Rect dirty);
invalidate(int left, int top, int right, int
bottom);

Views and layouts

If a window contains many views, it starts too slowly, takes too long to draw, and the user interface is slow to react

Solutions:

1. Composite drawable using textview reduces layers


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
0

2. Delay expanding the view using viewstuf

Define viewstuf in the xml file


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
1

When you need to expand the view,


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
2

3. use < merge > Merge intermediate view

By default, the root of the layout file is added to the superview as a node, which can be avoided if merge is used


<merge xmlns:android =
"http://schemas.android.com/apk/res/android">
<! -- Content -->
</merge>

4. Use ralativelayout to reduce levels


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
4

5. Use custom views


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
5

Use custom layouts


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
6

Memory allocation

Avoid creating java objects in performance-sensitive code

1. Measure onmeasure ()

2. Layout onlayout ()

3. Drawing ondraw () dispatchdraw ()

4. Event handling ontouchevent () dispatchtouchevent ()

5. adapter: getview ()

Impose restrictions (in debug mode)


public View getView(int pos, View convertView,
ViewGroup parent){
View item = mInflater.inflate(R.layout.list_item, null);
((TextView) item.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) item.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
7

Manage the target:

1. Apply soft references: the best choice for memory caching

2. Apply weak references: avoid memory leaks

Memory cache:


private final HashMap<String, SoftReference<T>> mCache;
public void put(String key, T value) {
mCache.put(key, new SoftReference<T>(value));
}
public T get(String key, ValueBuilder builder) {
T value = null;
SoftReferece<T> reference = mCache.get(key);
if (reference != null) {
value = reference.get();

Related articles: