17

我在我的应用程序的结构如下:的Android - 延迟点击ListView中

FragmentActivity与ViewPager持有使用compativility包由FragmentStatePagerAdapter管理的多个片段,片段的Android 2.1

每个片段包含ListViewListView中的每个元素都有一个LinearLayout,其中有两个TextViews和一个ButtonLinearLayout和按钮有onClickListeners(单独)。点击LinearLayout开始另一个Activity。我注意到点击行为非常不一致:有时行动立即执行,但很多时候会延迟,有时无论我点击多少次,行为都会被忽略。它变得更加怪异,因为我可以点击并且只有当我开始滚动列表时才会执行该动作。我尝试了setFocusable(false)setSelectable(true)的各种组合,但它似乎没有任何区别。有任何想法吗?我很乐意提供更多的细节。

回答

3

如果有人想知道我是如何解决这个问题的。基本上我不得不简化我的布局。看起来,当你有复杂的嵌套结构时,事件可能需要很长时间才能冒泡,并且如果你在同一时间开始滚动列表,事件可能触发错误的动作。我通过切换到RelativeLayout尽可能多地修剪布局,这似乎有很大的帮助

-1

看来你正在事件线程中执行一些阻塞过程(如调用webservices或打开文件),所以你的事件线程被阻塞。如果是这种情况,请将您的阻止代码处理为除事件THread以外的其他线程。

+0

我使用Loaders特别是AsyncLoader来完成我所有的后台进程。但我会重新评估代码,谢谢你的提示! – Bostone 2012-01-11 16:19:26

+0

毕竟不是理由。查看我的回答 – Bostone 2012-02-07 01:26:43

4

我遇到了同样的问题,但在我的情况下解决方案是不保留对视图的引用,导致ListView的视图出现问题缓存。在使用converView正确实施getView()方法之后,丢失/意外点击呼叫的所有奇怪行为都消失了。

+0

我在处理列表时总是在我的代码中使用处理程序模式 – Bostone 2012-03-23 23:06:44

+0

+1适合我。我保留对我的某个视图的引用(之后用于单个“ListView”行),原因是我不会进入这里 - 由于某种原因,这会导致对该项的所有点击延迟,直到该活动为止* *重新启动**,他们将全部流过并导致一系列例外。在适配器内部创建视图解决了这个问题 - 非常奇怪 – Dori 2013-03-21 15:44:13

1

对我而言有效的是将OnItemClickListener分配给ListViewsetOnItemClickListener,而不是将OnClickListener分配给各个列表项。显然,按钮仍然需要自己的OnClickListener,但我没有测试过这种情况。

9

我有一个类似的问题,花了我2​​天来调试和解决它。 我有一个ListAdapter为每个列表项在LinearLayout中创建几个TextView。 每个TextView都有它自己的OnClickListener,因为我需要处理每个项目的点击。

当我更改实现,以便重用Views时,OnClickListener停止正常工作。在4.4.2上,大多数点击都有效,但有时在我滚动列表之前没有任何反应。在2.3上,第一次点击将无法工作,然后在突发中处理所有点击。

在我的特殊情况下,我创建了Java代码中的所有视图,而不是通过膨胀资源。 关键的一点是,即使视图被重用(这似乎更安全,然后假定重用视图具有正确的布局参数),我仍然设置了LinearLayout的LayoutParams。 当我没有设置LayoutParams时,重用一切工作正常! 这里是关键代码:

public View getView(int position, View convertView, ViewGroup parent) { 
    LinearLayout tapeLine = null; 
    if (convertView != null && convertView instanceof LinearLayout && ((LinearLayout)convertView).getChildCount() == 4) tapeLine = (LinearLayout) convertView; // Reuse view 
    else tapeLine = new LinearLayout(activity); 
    if (convertView == null) { // Don't set LayoutParams when reusing view 
     ViewGroup.LayoutParams tapeLineLayoutParams = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
     tapeLine.setLayoutParams(tapeLineLayoutParams); 
    } 
    ScrollingTape scrollingTape = calculatorHolder.getCalculator().getScrollingTape(); 
    int tapeWidthPx = parent.getWidth(); 
    TapeLineTextSizeInfo tapeLineTextSizeInfo = calculatorHolder.getTapeLineTextSizeHelper().createTapeLineTextSizeInfo(tapeWidthPx); 
    ScrollingTapeLine line = scrollingTape.getLine(position); 
    tapeLine.setOrientation(LinearLayout.HORIZONTAL); 
    int tapeBackgroundColor = getBackgroundColor(line); 
    tapeLine.setBackgroundColor(tapeBackgroundColor); 
    addColumnViews(tapeLine, line, tapeLineTextSizeInfo); 
    tapeLine.setTag(R.id.scrollingtapeadapter_viewtag_position, position); 
    tapeLine.setOnLongClickListener(longClickListener); 
    tapeLine.setOnClickListener(remainClickListener); 
    return tapeLine; 
} 

什么是列表视图的这种奇怪的行为的背景是什么? 我在Android源代码中进行了一些调试和研究。 当android更新视图时,onMeasure和onLayout有两个重要步骤。 ListAdapter的getView方法不仅被调用来绘制视图,而且在onMeasure期间也被调用。在后面这种情况下,视图被创建,但它尚未在事件链中注册以处理点击事件。

当为onMeasure创建的视图稍后被重新用于画面时,它必须从Android系统注册以处理点击事件。 对于这种特殊情况,Android开发者已经做了一些事情,这可能被认为是肮脏的黑客攻击。 LayoutParams中的特殊标志用于决定视图必须在事件更改中注册。

现在我的问题:通过重置LayoutParams还视图重用时,此标志始终重置。因此,Android系统不会注册视图,事件不会通过。

总结:当在ListView的getView中重新使用视图时,不要覆盖LayoutParams,因为它们保留了android系统的内部信息。

+0

我有同样的问题。在我的情况下,布局不得不根据列表的数据源调整大小,所以当视图第一次膨胀时,我做了layout.params的更改,行项目上的点击再次正常工作。 – 2014-07-16 16:51:34

+0

OM * G,没办法,那是我的!那是倒退,晦涩和彻头彻尾的脑死亡。一个API是一个合同,这是一个不遵守。我已经失去了几个小时,不要让Google开发者在我身边。谢谢你不要让我为此疯狂。 – 2016-09-16 14:23:05

1

不知道这是否有助于任何人,但我有一个类似的问题,而不是TableLayout。上述解决方案没有解决我的问题。

对我的问题是: android:animateLayoutChanges="true"

删除这让我TableLayout行中我的按钮点击即可正常工作。我不得不手动地动画我的视图,而不是依靠上述属性。

+0

禁用动画也适用于我。 – 2017-06-14 08:50:05