问题描述
最近,我发现了的ListView
展开/折叠动画出现在 DialogFragment
比慢得多活动
。
Recently, I find out the ListView
expand/collapse animation appears much slower in DialogFragment
than in Activity
.
在 DialogFragment
,动画FPS为10帧。每个动画需要100毫秒。
In DialogFragment
, the animation FPS is 10 fps. Each animation takes 100ms.
在活动
,动画FPS为50帧。每个动画需要20毫秒。
In Activity
, the animation FPS is 50 fps. Each animation takes 20ms.
我把这个美好的开源库为基准例如:,在 DialogFragment
之间的性能测试和活动
。
I made modification on https://github.com/nhaarman/ListViewAnimations/blob/master/example/src/com/haarman/listviewanimations/itemmanipulationexamples/ItemManipulationsExamplesActivity.java#L51, to test between performance in DialogFragment
and 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");
}
我在https://github.com/nhaarman/ListViewAnimations/blob/master/example/src/com/haarman/listviewanimations/itemmanipulationexamples/ExpandableListItemActivity.java
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);
}
}
}
然后,我把我的基准code在该文件中: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
的性能?
我把整个项目的文件,以防万一你有兴趣测试一下。
I place the entire project files, just in case you're interested to test out.
通过使用TraceView跟踪,我发现,使用 DialogFragment
来展开的ListView
项中,<$ C $时C> ArrayAdapter 将被称为频繁。我不知道是什么原因它是如此。我做的另一个独立的实现,而无需使用开源库。我仍然面临着同样的问题。
By tracing using TraceView, I notice that when using DialogFragment
to expand ListView
item, the ArrayAdapter
will be called frequent. I'm not exactly sure why it is so. I do another independent implementation without using the open source library. I'm still facing the same problem.
在 DialogFragment
执行动画中, ArrayAdapter
的 getView
将同时动画过程中被频繁触发。
Perform animation on DialogFragment
, the ArrayAdapter
's getView
will be triggered frequently while animation is in progress.
的活动,当动画正在进行中, ArrayAdapter
的 getView
不会被触发。
For Activity, when animation is in progress, ArrayAdapter
's getView
will NOT be triggered.
TraceView同时使用DialogFragment
TraceView while using DialogFragment
TraceView而使用活动
TraceView while using Activity
推荐答案
我找出关键解决这个问题,始终修复对话框的大小。一旦我们解决大小,没有资源将用于动画制作过程中执行的大小计算。
I find out the key solution to this problem is, fix the dialog size always. Once we fix the size, no resource will be spent to perform size computation during animation.
final ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Key area to perform optimization. Fix the dialog size!
// During ListView's rows animation, dialog will never need to
// perform computation again.
int width = dialog.getWindow().getDecorView().getWidth();
int height = dialog.getWindow().getDecorView().getHeight();
dialog.getWindow().setLayout(width, height);
ViewTreeObserver obs = view.getViewTreeObserver();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
obs.removeOnGlobalLayoutListener(this);
} else {
obs.removeGlobalOnLayoutListener(this);
}
}
});
这篇关于为什么ListView的展开/折叠动画出现在DialogFragment比活动慢得多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!