为什么ListView的展开/折叠动画出现在DialogFragment比活动慢得多 [英] Why ListView expand/collapse animation appears much slower in DialogFragment than in Activity

查看:257
本文介绍了为什么ListView的展开/折叠动画出现在DialogFragment比活动慢得多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我发现了的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.

我把这个美好的开源库为基准例如: https://github.com/nhaarman/ListViewAnimations

I took this wonderful open source library as benchmark example : https://github.com/nhaarman/ListViewAnimations

我在<一做修改href=\"https://github.com/nhaarman/ListViewAnimations/blob/master/example/src/com/haarman/listviewanimations/itemmanipulationexamples/ItemManipulationsExamplesActivity.java#L51\" rel=\"nofollow\">https://github.com/nhaarman/ListViewAnimations/blob/master/example/src/com/haarman/listviewanimations/itemmanipulationexamples/ItemManipulationsExamplesActivity.java#L51,在 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");        
    }

我在<一个做了细微的修改href=\"https://github.com/nhaarman/ListViewAnimations/blob/master/example/src/com/haarman/listviewanimations/itemmanipulationexamples/ExpandableListItemActivity.java\" rel=\"nofollow\">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在该文件中:<一href=\"https://github.com/nhaarman/ListViewAnimations/blob/master/library/src/com/haarman/listviewanimations/itemmanipulation/ExpandableListItemAdapter.java#L277\" rel=\"nofollow\">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.

https://www.dropbox.com/s/5q6ttn11o92g39n/ListViewAnimations- master.zip

通过使用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比活动慢得多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆