最近,我发现ListView
展开/折叠动画DialogFragment
在Activity
.
在DialogFragment
中,动画 FPS 为 10 fps。每个动画需要 100 毫秒。
在Activity
中,动画 FPS 为 50 fps。每个动画需要 20 毫秒。
我把这个很棒的开源库作为基准示例:https ://github.com/nhaarman/ListViewAnimations
我在https://github.com/nhaarman/ListViewAnimations/blob/master/example/src/com/haarman/listviewanimations/itemmanipulationexamples/ItemManipulationsExamplesActivity.java#L51上进行了修改,以测试DialogFragment
和之间的性能Activity
。
public void onExpandListItemAdapterClicked(View view) {
// For Activity testing.
Intent intent = new Intent(this, ExpandableListItemActivity.class);
startActivity(intent);
// For DialogFragment testing.
//FragmentManager fm = this.getSupportFragmentManager();
//DemoDialogFragment demoDialogFragment = new DemoDialogFragment();
//demoDialogFragment.show(fm, "DemoDialogFragment");
}
public class ExpandableListItemActivity extends MyListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyExpandableListItemAdapter myExpandableListItemAdapter = new MyExpandableListItemAdapter(this, getItems());
//AlphaInAnimationAdapter alphaInAnimationAdapter = new AlphaInAnimationAdapter(myExpandableListItemAdapter);
//alphaInAnimationAdapter.setAbsListView(getListView());
getListView().setAdapter(myExpandableListItemAdapter);
Toast.makeText(this, R.string.explainexpand, Toast.LENGTH_LONG).show();
}
我创建了自己DialogFragment
的测试类。完全基于ExpandableListItemActivity
package com.haarman.listviewanimations.itemmanipulationexamples;
import java.util.ArrayList;
import java.util.List;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.haarman.listviewanimations.ArrayAdapter;
import com.haarman.listviewanimations.R;
import com.haarman.listviewanimations.itemmanipulation.ExpandableListItemAdapter;
public class DemoDialogFragment extends DialogFragment {
private ListView mListView;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mListView = new ListView(getActivity());
mListView.setDivider(null);
MyExpandableListItemAdapter myExpandableListItemAdapter = new MyExpandableListItemAdapter(getActivity(), getItems());
//AlphaInAnimationAdapter alphaInAnimationAdapter = new AlphaInAnimationAdapter(myExpandableListItemAdapter);
//alphaInAnimationAdapter.setAbsListView(getListView());
getListView().setAdapter(myExpandableListItemAdapter);
Toast.makeText(getActivity(), R.string.explainexpand, Toast.LENGTH_LONG).show();
final AlertDialog dialog = new AlertDialog.Builder(this.getActivity())
.setView(mListView)
.create();
return dialog;
}
public ListView getListView() {
return mListView;
}
protected ArrayAdapter<Integer> createListAdapter() {
return new MyListAdapter(getActivity(), getItems());
}
public static ArrayList<Integer> getItems() {
ArrayList<Integer> items = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
items.add(i);
}
return items;
}
private static class MyListAdapter extends ArrayAdapter<Integer> {
private Context mContext;
public MyListAdapter(Context context, ArrayList<Integer> items) {
super(items);
mContext = context;
}
@Override
public long getItemId(int position) {
return getItem(position).hashCode();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = (TextView) convertView;
if (tv == null) {
tv = (TextView) LayoutInflater.from(mContext).inflate(R.layout.list_row, parent, false);
}
tv.setText("This is row number " + getItem(position));
return tv;
}
}
private static class MyExpandableListItemAdapter extends ExpandableListItemAdapter<Integer> {
private Context mContext;
private LruCache<Integer, Bitmap> mMemoryCache;
/**
* Creates a new ExpandableListItemAdapter with the specified list, or an empty list if
* items == null.
*/
private MyExpandableListItemAdapter(Context context, List<Integer> items) {
super(context, R.layout.activity_expandablelistitem_card, R.id.activity_expandablelistitem_card_title, R.id.activity_expandablelistitem_card_content, items);
mContext = context;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory;
mMemoryCache = new LruCache<Integer, Bitmap>(cacheSize) {
@Override
protected int sizeOf(Integer key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
};
}
@Override
public View getTitleView(int position, View convertView, ViewGroup parent) {
TextView tv = (TextView) convertView;
if (tv == null) {
tv = new TextView(mContext);
}
tv.setText(mContext.getString(R.string.expandorcollapsecard, getItem(position)));
return tv;
}
@Override
public View getContentView(int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if (imageView == null) {
imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
int imageResId;
switch (getItem(position) % 5) {
case 0:
imageResId = R.drawable.img_nature1;
break;
case 1:
imageResId = R.drawable.img_nature2;
break;
case 2:
imageResId = R.drawable.img_nature3;
break;
case 3:
imageResId = R.drawable.img_nature4;
break;
default:
imageResId = R.drawable.img_nature5;
}
Bitmap bitmap = getBitmapFromMemCache(imageResId);
if (bitmap == null) {
bitmap = BitmapFactory.decodeResource(mContext.getResources(), imageResId);
addBitmapToMemoryCache(imageResId, bitmap);
}
imageView.setImageBitmap(bitmap);
return imageView;
}
private void addBitmapToMemoryCache(int key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
private Bitmap getBitmapFromMemCache(int key) {
return mMemoryCache.get(key);
}
}
}
然后,我将我的基准代码放在这个文件中:https ://github.com/nhaarman/ListViewAnimations/blob/master/library/src/com/haarman/listviewanimations/itemmanipulation/ExpandableListItemAdapter.java#L277
private ValueAnimator createHeightAnimator(int start, int end) {
Log.i("CHEOK", start + " -> " + end);
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = mContentParent.getLayoutParams();
layoutParams.height = value;
Log.i("CHEOK", "height = " + value);
mContentParent.setLayoutParams(layoutParams);
}
});
return animator;
}
这是我得到的结果
// Using DialogFragment
10-12 03:36:05.695: I/CHEOK(29407): height = 0
10-12 03:36:06.258: I/CHEOK(29407): height = 0
10-12 03:36:06.347: I/CHEOK(29407): height = 74
10-12 03:36:06.547: I/CHEOK(29407): height = 358
10-12 03:36:06.621: I/CHEOK(29407): height = 360
// Using Activity
10-12 03:37:02.375: I/CHEOK(29956): height = 0
10-12 03:37:02.387: I/CHEOK(29956): height = 0
10-12 03:37:02.406: I/CHEOK(29956): height = 3
10-12 03:37:02.461: I/CHEOK(29956): height = 51
10-12 03:37:02.476: I/CHEOK(29956): height = 72
10-12 03:37:02.492: I/CHEOK(29956): height = 98
10-12 03:37:02.512: I/CHEOK(29956): height = 131
10-12 03:37:02.531: I/CHEOK(29956): height = 164
10-12 03:37:02.547: I/CHEOK(29956): height = 196
10-12 03:37:02.562: I/CHEOK(29956): height = 228
10-12 03:37:02.582: I/CHEOK(29956): height = 260
10-12 03:37:02.601: I/CHEOK(29956): height = 290
10-12 03:37:02.617: I/CHEOK(29956): height = 312
10-12 03:37:02.633: I/CHEOK(29956): height = 331
10-12 03:37:02.652: I/CHEOK(29956): height = 348
10-12 03:37:02.672: I/CHEOK(29956): height = 357
10-12 03:37:02.687: I/CHEOK(29956): height = 360
有什么想法,为什么会这样?我们如何提高性能DialogFragment
?
我放置了整个项目文件,以防您有兴趣测试。
https://www.dropbox.com/s/5q6ttn11o92g39n/ListViewAnimations-master.zip
更新
通过使用 TraceView 进行跟踪,我注意到在使用DialogFragment
展开ListView
item 时,ArrayAdapter
会调用频繁。我不确定为什么会这样。我在不使用开源库的情况下做了另一个独立的实现。我仍然面临同样的问题。
在 上执行动画DialogFragment
,在动画进行时ArrayAdapter
会getView
频繁触发 。
对于 Activity,当动画正在进行时,不会触发ArrayAdapter
's 。getView
使用 DialogFragment 时的 TraceView
使用 Activity 时的 TraceView