Horizo​​ntalScrollView:带有getView()的CustomAdapter不重用像ListView这样的convertViews

时间:2014-10-13 13:48:51

标签: android android-adapter horizontalscrollview

在我过去的一个项目中,我实施了“Time Picker Carousel”。它基于HorizontalScrollView。用户可以在滚动此视图时选择时间。时间值是根据HorizontalScrollView的X-Offset计算的。

enter image description here

我想在github上分享这个项目,但在清理代码时我发现了一些性能不佳问题。

HorizontalScrollView填充了自定义ArrayAdaptergetView() Holder使用convertView。我认为它可能在ListView中作为适配器工作,因此只有可见项才会被销毁并重新使用它们。相反,所有项目都被渲染!!! (在我的情况下是1008!)我自己添加它们(代码示例中为#1),但即使我尝试添加更少,但删除(和回收)旧的逻辑不起作用,或者我是想念什么?

所以我的基本问题是:我需要更改什么才能使我的适配器的行为类似于ListView

  1. 我找到了this so link并试图覆盖remove函数,但这从未调用过(不知何故逻辑,因为我只是添加)
  2. 在github上有一个很好的PagerAdapter example,但不知怎的,我无法将其转换为ArrayAdapter<String>
  3. 欢迎任何想法,链接!

    请不要建议使用ListView。我们决定使用HorizontalScrollView因为回调以及我们在布局中已经有ListView的事实。

    Horizo​​ntalScrollView

    InfiniteTimeScrubberHorizontalView extends HorizontalScrollView{
    ...
    public void setAdapter(Context context, TimeScrubberListAdapter mAdapter) {
        this.mAdapter = mAdapter;
        try {
            fillViewWithAdapter(mAdapter);
        } catch (ZeroChildException e) {
            e.printStackTrace();
        }
    }
    
    private void fillViewWithAdapter(TimeScrubberListAdapter mAdapter) {
        //...
    
        ViewGroup parent = (ViewGroup) getChildAt(0);
        parent.removeAllViews();
        for (int i = 0; i < mAdapter.getCount(); i++) {
            //#1: Here: ALL views are added
            parent.addView(mAdapter.getView(i, null, parent));   
        }
    }
    

    Adpater

    public class TimeScrubberListAdapter extends ArrayAdapter<String> {
    
    //...
    private ArrayList<String> list;  //list from 0:00,0:30...23:00,23:30
    final static int MAXIMUM_DAYS = 21
    
    @Override
    public int getCount() {
        return list.size() * MAXIMUM_DAYS;
    }
    
    @Override
    public String getItem(int position) {
        return list.get(position % list.size());
    }
    
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        RelativeLayout layout;
    
        if (convertView == null) {
            layout = (RelativeLayout) View.inflate(context, layoutId, null);
            holder = new Holder();
            holder.title = (TextView) layout.findViewById(R.id.epg_item_text);
            layout.setTag(holder);
        } else {
            layout = (RelativeLayout) convertView;
            view = layout;
            holder = (Holder) layout.getTag();
        }
    
        layout.setLayoutParams(mLP);        
    
        String timeValue = getItem(position);
        holder.title.setText(timeValue);            
    
        return layout;
    }
    //...
    @Override
    public void remove(String object) {
        //not called...some how logic, because i do not remove an item
        super.remove(object);    
    }
    

2 个答案:

答案 0 :(得分:15)

我想也许你会混淆视图和适配器之间渲染的逻辑。使用适配器不会导致视图回收行为。 ListView本身及其父级AbsListView实现了视图回收行为。 ListView需要适配器才能正确填充屏幕上显示的视图,但是实际选择要显示哪些视图以及何时以及如何回收这些视图的逻辑不在适配器中所有

如果您查看HorizontalScrollViewListView的源代码,您会发现它们截然不同。它们不同的方向不同。

因此,它的长短之处在于,您无法使用HorizontalScrollView甚至是简单的后代来获取您正在寻找的视图回收。如果您想要查看回收,请查看RecyclerView

答案 1 :(得分:2)

ScrollView将所有子视图保留在内存中,因此在使用它们时性能问题很常见。

为什么不使用一些开源的Horizo​​ntalListView库。 在搜索时,我得到了这两个库,我在其中一个项目中使用了第一个库,它运行顺利,没有任何内存问题。

这些库是ListView的水平实现,它根据屏幕上可见的视图为您回收项目。 Scrollview不适用于无限滚动视图。

更新:现在我们有来自Android的RecyclerView,它也支持水平滚动,它还强制使用 Viewholder 模式