Android HorizontalScrollView:getView()的CustomAdapter不';不要重用像ListView这样的视图

Android HorizontalScrollView:getView()的CustomAdapter不';不要重用像ListView这样的视图,android,android-adapter,horizontalscrollview,Android,Android Adapter,Horizontalscrollview,在我过去的一个项目中,我实现了一个“时间选择器转盘”。它基于水平滚动视图。用户可以在滚动此视图时选择时间。时间值根据水平滚动视图的X偏移量计算得出 我想在github上分享这个项目,但是在清理代码时,我意识到了一些性能不好的问题 HorizontalScrollView中填充了一个自定义的ArrayAdapter。getView()为convertView使用一个Holder。我认为它可以作为列表视图中的适配器使用,因此只有可见项才会被呈现和重用(如果它们将被销毁)。相反,将渲染所有项目!!!

在我过去的一个项目中,我实现了一个“时间选择器转盘”。它基于
水平滚动视图
。用户可以在滚动此视图时选择时间。时间值根据
水平滚动视图的X偏移量计算得出

我想在github上分享这个项目,但是在清理代码时,我意识到了一些性能不好的问题

HorizontalScrollView
中填充了一个自定义的
ArrayAdapter
getView()
convertView
使用一个
Holder
。我认为它可以作为
列表视图
中的适配器使用,因此只有可见项才会被呈现和重用(如果它们将被销毁)。相反,将渲染所有项目!!!(在我的例子1008!)我自己添加了它们(在代码示例中为1),但即使我尝试添加较少的内容,删除(和回收)旧内容的逻辑也不起作用,或者我遗漏了什么

因此,我的基本问题是:我必须做哪些更改才能使适配器的行为类似于
ListView

  • 我找到并尝试重写
    remove
    函数,但从未调用过该函数(出于某种逻辑,因为我只是在添加)
  • github有一个很好的功能,但不知何故我无法将其转换为
    ArrayAdapter
  • 欢迎任何想法、链接

    请不要建议改用
    ListView
    。我们决定使用
    HorizontalScrollView
    ,因为回调和布局中已有
    ListView
    的事实

    水平滚动视图

    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));   
        }
    }
    
    InfiniteMesCrubberhorizontalview扩展了水平滚动视图{
    ...
    public void setAdapter(上下文上下文,timescrubberlistatadapter mAdapter){
    this.mAdapter=mAdapter;
    试一试{
    用适配器填充视图(mAdapter);
    }捕获(零异常){
    e、 printStackTrace();
    }
    }
    专用void fillview with adapter(timescrubberlistatadapter mAdapter){
    //...
    ViewGroup parent=(ViewGroup)getChildAt(0);
    parent.removeallview();
    对于(int i=0;i
    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);    
    }
    
    公共类TimeScrubberListAdapter扩展了ArrayAdapter{
    //...
    private ArrayList;//0:00,0:30…23:00,23:30之间的列表
    最终静态整数最大天数=21天
    @凌驾
    public int getCount(){
    退货清单.size()*最长天数;
    }
    @凌驾
    公共字符串getItem(int位置){
    返回list.get(位置%list.size());
    }
    @凌驾
    公共视图getView(最终整数位置、视图转换视图、视图组父视图){
    相对布局;
    if(convertView==null){
    布局=(RelativeLayout)视图。膨胀(上下文,布局ID,null);
    保持架=新保持架();
    holder.title=(TextView)layout.findViewById(R.id.epg\u item\u text);
    布局。设置标签(支架);
    }否则{
    布局=(RelativeLayout)转换视图;
    视图=布局;
    holder=(holder)layout.getTag();
    }
    布局。设置布局参数(mLP);
    字符串时间值=getItem(位置);
    holder.title.setText(时间值);
    返回布局;
    }
    //...
    @凌驾
    公共无效删除(字符串对象){
    //不叫…有些怎么逻辑,因为我不删除一个项目
    超级。移除(对象);
    }
    
    我认为您可能混淆了视图和适配器之间渲染的逻辑所在。使用适配器不会导致视图循环行为。实现视图循环行为的是
    ListView
    本身及其父级
    AbsListView
    。中的
    ListView
    需要适配器为了根据需要正确填充屏幕上显示的视图,但实际选择要显示哪些视图以及何时以及如何回收这些视图的逻辑根本不在适配器中

    如果你看一下for和for的源代码,你会发现它们有很大的不同。它们在不同的方向上不只是同一件事


    因此,长话短说,使用
    HorizontalScrollView
    甚至一个简单的子视图,您将无法获得正在寻找的视图循环。如果您想要视图循环,您应该查看。

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

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

    这些LIB是ListView的水平实现,它根据屏幕上可见的视图为您回收项目。Scrollview是有限滚动视图的错误选择。


    更新:现在我们从Android本身开始,它也支持水平滚动,它还强制使用模式

    您尝试过使用HorizontalListView的一些实现吗?好的,一开始我们决定使用
    滚动视图
    而不是
    HorizontalListView
    …但是我会的如果无法找到当前问题的解决方案,请尝试添加以下内容:if(convertView==null&&convertView.isVisible())。请注意,这是一个在黑暗中拍摄的照片。希望对您有所帮助。我建议您看看如何在listview中实现视图回收。您是否检查了RecyclerView?使用Android L拍摄,但您可以对其进行后移。查看此s.o.帖子感谢您的回答,仍在为其寻找回收解决方案scrollview@longilong祝你好运,回收利用视图不是琐碎的,也不能简单地被黑客攻击到一个滚动视图上。好吧,也许我会打开潘多拉星球