【问题标题】:how to make a smooth animation when listview is doing RequestLayout()listview在做RequestLayout()时如何制作流畅的动画
【发布时间】:2015-08-04 04:05:52
【问题描述】:

我在一个按钮上实现了一个旋转动画,效果很好。

当我把它放在action bar上,然后在window的内容中调用RequestLayout()上一个ListView,动画就开始掉帧了。

由于RequestLayout()会挂掉主线程,所以有两种解决方案:

  1. 逐行手动更新ListView,每40ms释放一次主线程
  2. 找一个“高优先级”的动画,即使主线程忙也能继续播放

虽然第一个解决方案值得一试,但我不知道如何实施第二个解决方案。

希望您的建议。 ;)

在我的实际项目中,动画是一个简单的旋转动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator">
<rotate 
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="500" /> 

</set>

下面的代码是我用来测试ListView的demo。虽然和上面的动画没有关系,但是当我更新ListView的数据时,通过手机提供的GPU开发者工具可以看到android开始掉帧了。

在实际项目中,listview的数据更新时,动画会出现卡顿。

主活动:

public class MainActivity extends Activity {


public static int N_ROW = 200;

    private ListView mListView;
    private ArrayList<String> mData1 = null;
    private ArrayList<String> mData2 = null;
    private ArrayList<String> mData3 = null;
    private int mCurrData = 1;
    private Random r = new Random();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.listView);

        /// random, 3-digits test data to display in listview
        mData1 = genRandomData(0);

        /// longer test data 
        mData2 = genRandomData(100000);

        /// another test data to change content of textView but do not change the content length
        mData3 = genRandomData(0);

        final ListViewAdapter adapter = new ListViewAdapter(this, R.layout.list_item_name, mData1);
        mListView.setAdapter(adapter);

        /// change the text using standard notifyDataSetChanged
        Button btn = (Button) findViewById(R.id.button);
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCurrData == 1) {
                    mCurrData = 3;
                    adapter.updateData(mData3);
                } else {
                    mCurrData = 1;
                    adapter.updateData(mData1);
                }

                adapter.notifyDataSetChanged();
            }

        });


        /// change the text length between long <---> short  & invalidate()
        Button btn1 = (Button) findViewById(R.id.btn_invalidate);
        btn1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCurrData == 2) {
                    mCurrData = 1;
                    adapter.updateData(mData1);
                } else {
                    mCurrData = 2;
                    adapter.updateData(mData2);
                }

                refreshVisibleListViewArea();
                mListView.invalidate();
            }
        });


        /// change the text using row by row modification & invalidate()
        Button btn2 = (Button) findViewById(R.id.btn_invalidate2);
        btn2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCurrData == 3) {
                    mCurrData = 1;
                    adapter.updateData(mData1);
                } else {
                    mCurrData = 3;
                    adapter.updateData(mData3);
                }
                refreshVisibleListViewArea();
                mListView.invalidate();
            }
        });


        /// do nothing but invalidate()
        Button btn3 = (Button) findViewById(R.id.btn_invalidate3);
        btn3.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                refreshVisibleListViewArea();
                mListView.invalidate();
            }
        });
    }

    private ArrayList<String> genRandomData(int offset) {
        ArrayList<String> tmp = new ArrayList<String>();

        for (int i = 0; i < N_ROW * 4; ++ i) {
            String a = "I_" + r.nextInt(N_ROW * 4 + offset);
            tmp.add(a);
        }

        return tmp;
    }

    private void refreshVisibleListViewArea() {
        int s = mListView.getFirstVisiblePosition();
        int e = mListView.getLastVisiblePosition();
        for (int i = s; i <= e; ++ i) {
            View v = mListView.getChildAt(i - s);
            mListView.getAdapter().getView(i, v, mListView);
        }
    }
}

适配器:

public class ListViewAdapter extends ArrayAdapter<String> {


    private ArrayList<String> mData;
    private Context mContext;

    public ListViewAdapter(Context context, int resource, ArrayList<String> data) {
        super(context, resource, data);
        mContext = context;
        mData = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder vh = null;
        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.list_item_name, parent, false);
            vh = new ViewHolder();

            vh.v1 = (TextView) convertView.findViewById(R.id.v1);
            vh.v2 = (TextView) convertView.findViewById(R.id.v2);
            vh.v3 = (TextView) convertView.findViewById(R.id.v3);
            vh.v4 = (TextView) convertView.findViewById(R.id.v4);

            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }

        if (vh.v1.getText() != mData.get(position * 4)) {
            vh.v1.setText(mData.get(position * 4));
        }
        if (vh.v2.getText() != mData.get(position * 4 + 1)) {
            vh.v2.setText(mData.get(position * 4 + 1));
        }
        if (vh.v3.getText() != mData.get(position * 4 + 2)) {
            vh.v3.setText(mData.get(position * 4 + 2));
        }
        if (vh.v4.getText() != mData.get(position * 4 + 3)) {
            vh.v4.setText(mData.get(position * 4 + 3));
        }
        return convertView;
    }

    public int getCount() {
        return MainActivity.N_ROW;
    }

    public void updateData(ArrayList<String> data) {
        mData = data;
    }

    class ViewHolder {
        TextView v1;
        TextView v2;
        TextView v3;
        TextView v4;
    }

}

list_item xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/v1"
        android:layout_width="80dp"
        android:layout_height="30dp"
        android:background="#f00"
        android:ellipsize="none"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/v2"
        android:layout_width="80dp"
        android:layout_height="30dp"
        android:background="#0f0"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/v3"
        android:layout_width="80dp"
        android:layout_height="30dp"
        android:background="#00f"
        android:ellipsize="none"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/v4"
        android:layout_width="80dp"
        android:layout_height="30dp"
        android:background="#0ff"
        android:ellipsize="none"
        android:textSize="16sp" />


</LinearLayout>

【问题讨论】:

  • 为什么RequestLayout()会挂掉他的主线程?
  • 你能告诉你的代码你到底想做什么
  • @pskink:我的意思是在我调用 RequestLayout() 之后,主线程似乎挂了一段时间(以更新列表视图)。我将代码的sn-ps粘贴到线程中
  • 你为什么在refreshVisibleListViewArea中打电话给getView?
  • getView() 将调用 convertView.getTag(),然后更新列表项中的 4 个 textView。如果错过此调用,ListView 的可见区域将无法正确更新。

标签: android listview animation


【解决方案1】:

经过一些 profiling 工作,我相信在我上面描述的情况下,有太多的 TextViews 需要同时更新,所以 opengl draw 占用了很多资源。

决定将 udpate 拆分成更小的部分。


最后我使用表面视图来实现动画效果。 ;)

【讨论】:

    猜你喜欢
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    • 2014-01-16
    • 1970-01-01
    相关资源
    最近更新 更多