【问题标题】:Scrolling down in custom ListView makes the Item's Spinner empty在自定义 ListView 中向下滚动会使 Item 的 Spinner 为空
【发布时间】:2014-08-06 19:53:18
【问题描述】:

我有一个带有自定义 ArrayAdapter 和自定义项的 ListView。这些项目包含多个视图元素,包括一个 Spinner。这个 Spinner 的 ArrayAdapter 是这样设置的:

// Method to set or update the Tags in the Spinner
public void updateTagsSpinner(MyHolder h, Spinner sp){
    if(h != null && h.orderedProductItem != null){
        // If the given Spinner null, it means we change the OrderedProductItem's Spinner
        // Is the given Spinner not null, it means we change the Manage Tag's PopupWindow's Spinner
        if(sp == null)
            sp = h.spTags;

        // We know it's an ArrayAdapter<String> so we just ignore the 
        // "Unchecked cast from SpinnerAdapter to ArrayAdapter<String>" warning
        @SuppressWarnings("unchecked")
        ArrayAdapter<String> spAdapt = (ArrayAdapter<String>) sp.getAdapter();
        ArrayList<String> tagStrings = Controller.getInstance().getAllTagsWithOrderedProductItem(h.orderedProductItem));
        if(tagStrings != null && tagStrings.size() > 0){
            if(spAdapt == null){
                spAdapt = new ArrayAdapter<String>(ChecklistActivity.this, android.R.layout.simple_spinner_item, tagStrings);
                spAdapt.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                // ArrayAdapter's setNotifyOnChange is true by default,
                // but I set it nonetheless, just in case
                spAdapt.setNotifyOnChange(true);
                sp.setAdapter(spAdapt);
            }
            else{
                spAdapt.clear();
                spAdapt.addAll(tagStrings);
            }
        }
        sp.setSelection(h.orderedProductItem.getSelectedFilter());
    }
}

由于某种原因,每次我向下滚动然后再次向上滚动时,我的 Spinner 都是空的。当我点击它们时,我什至无法再打开任何 Spinner(包括那些不为空的),因为警告:

W/InputEventReceiver(899):尝试完成输入事件,但输入事件接收器已被释放。

【问题讨论】:

    标签: android android-listview android-arrayadapter android-spinner


    【解决方案1】:

    好的,我发现了这个问题,这是一个令人讨厌的问题。这就是我发布问题/答案以帮助其他有类似问题的人的原因。

    警告:adapter.clear() 会更改已被 ArrayAdapter 使用的原始列表!!

    在我的控制器中,我有一个带有 key = int productId 和 value = ArrayList&lt;String&gt; productTags 的 HashMap (allTagsOfProducts)。在 getAllTagsWithOrderedProductItem 方法中,我使用以下内容:

    public ArrayList<String> getAllTagsWithOrderedProductItem(OrderedProductItem opi){
        if(opi != null && opi.getProductId() > 0){
            // Check if a new Tag has been added / removed
            if(getProductById(opi.getProductId()).getTagsHasChanged()){
                ArrayList<String> newProductTags = new ArrayList<String>();
    
                ... // Do some stuff to fill the newProductTags-List
    
                // Replace the previously saved Tags of this Products with this updated one
                allTagsOfProduct.put(opi.getProductId(), newProductTags);
                // Set the boolean on false
                getProductById(opi.getProductId()).setTagsHasChanged(false);
                // And return this update list
                return newProductTags;
            }
            // If nothing is added / removed, just return the list we already saved
            else
                return allTagsOfProduct.get(opi.getProductId());
        }
        // If the given OrderedProductItem is null return an empty list
        else
            return new ArrayList<String>();
    }
    

    当我调试这个时,我发现当我第一次进入return allTagsOfProduct.get(opi.getProductId());的else时,一切正常,当我再次进入这里时,HashMap中保存的ArrayList是空的([]) .. 我能想到的唯一原因是 ArrayAdapter 的 .clear() 方法。因此,我不得不使用新的 ArrayList,而无需在 Controller 的 HashMap 中引用 ArrayList。

    TL;DR: 我的问题帖子中的ArrayList&lt;String&gt; tagStrings = Controller.getInstance().getAllTagsWithOrderedProductItem(h.orderedProductItem)); 行替换为:

    // We create a new ArrayList here, since spAdapt.clear() changes the original list
    // all the way into the Controller's HashMap.. You gotta love the Java references.. >.>
    ArrayList<String> tagStrings = new ArrayList<String>(
        Controller.getInstance().getAllTagsWithOrderedProductItem(h.orderedProductItem));
    

    PS:我也无法再打开非空 Spinner 并且它给了我警告的原因是因为自定义 ArrayAdapter(在这种情况下是我的 ListView)的 getView() 回收原则。 Click this link for more information of how ListView's getView() recycling works. 它将项目的微调器重新用于另一个项目。因此,即使这个新 Item 的 Spinner 被其他 Item 的 ArrayList/ArrayAdapter 正确填充,Input-EventHandler 也不会重置,所以我仍然会收到此警告,用于回收 ListView-Item 中的非空 Spinner。

    【讨论】:

      猜你喜欢
      • 2017-08-10
      • 2021-12-16
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 2021-08-01
      • 1970-01-01
      • 2021-07-17
      • 2011-10-16
      相关资源
      最近更新 更多