我有一个自定义 Listview,它使用适配器类来扩展 Item 类的 ArrayAdapter。我可以在 NONE、Single 和 Multi 的选择模式之间切换。这一切都很好。我现在要实现的是一种在多选模式下通过多选从 ListView (和适配器)中删除项目的方法。但是,在执行以下任一操作时,我得到 IndexOutOFBounds 异常; 1)在单选模式下删除 ListView 中的最后一项(注意:最后一项删除之前的任何内容都可以) 2)在多选选择模式下,我再次无法删除最后一项 3) 再次在多选模式下,我可以删除最后一个项目之前的单个选定项目,但 2 个或更多选择会再次导致索引越界错误。
我添加了调试日志以显示被移除的位置和 getCheckItemPositions() 的大小以及我的 for 循环计数器(例如 i),最后是被移除项目的项目标题。如果我注释掉实际的 listadpter.remove(position) 行,那么日志输出似乎表明一切正常所以我现在怀疑问题出在我的适配器类 getView 方法中。但是我的大脑已经筋疲力尽,我被困住了。
MainActivity.class - 从按钮 View 对象调用的 removeItems 方法;
private void removeItems() {
final SparseBooleanArray checkedItems = listView.getCheckedItemPositions();
//final long[] checkedItemIds = listView.getCheckedItemIds();
final int checkedItemsCount = checkedItems.size();
Log.d("drp", "Adapter Count is: " + Integer.toString(mMyListViewAdapter.getCount()));
if (checkedItems != null) {
for (int i = checkedItemsCount-1; i >= 0 ; --i) {
// This tells us the item position we are looking at
// --
final int position = checkedItems.keyAt(i);
// This tells us the item status at the above position
// --
final boolean isChecked = checkedItems.valueAt(i);
if (isChecked) {
Item item = mMyListViewAdapter.getItem(position);
Log.d("drp", "removing : " + Integer.toString(position) + " of " +Integer.toString(checkedItemsCount) + "-" + Integer.toString(i) + " - Title: " + mMyListViewAdapter.getItem(position).getTitle());
mMyListViewAdapter.remove(item);
}
}
}
}
适配器类;
public class MyListViewAdapter extends ArrayAdapter<Item> implements OnItemClickListener{
private LayoutInflater mInflator;
/**
* This is my view holder for getView method so don't need to call
* findViewById all the time which results in speed increase
*/
static class ViewHolder {
public TextView txtTitle;
public TextView txtDescription;
public TextView txtSessionCount;
public ImageView listThumbnailImage;
public ImageView listStatusIndicatorImage;
public InertCheckBox Checkbox;
}
/**
* Constructor from a list of items
*/
public MyListViewAdapter(Context context, List<Item> items) {
super(context, 0, items);
mInflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// This is how you would determine if this particular item is checked
// when the view gets created
// --
final ListView lv = (ListView) parent;
final boolean isChecked = lv.isItemChecked(position);
final int selectionMode = lv.getChoiceMode();
// The item we want to get the view for
// --
Item item = getItem(position);
// Re-use the view if possible (recycle)
// --
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflator.inflate(R.layout.listview_row, null);
holder = new ViewHolder();
holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
holder.txtDescription = (TextView) convertView.findViewById(R.id.description);
holder.txtSessionCount = (TextView) convertView.findViewById(R.id.session_count);
holder.listThumbnailImage = (ImageView) convertView.findViewById(R.id.list_image);
holder.listStatusIndicatorImage = (ImageView) convertView.findViewById(R.id.status);
holder.Checkbox = (InertCheckBox) convertView.findViewById(R.id.inertCheckBox);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.txtTitle.setText(item.getTitle());
holder.txtDescription.setText(item.getDescription());
holder.txtSessionCount.setText(item.getSessionCount());
holder.listThumbnailImage.setImageBitmap((Bitmap) item.getThumbnailImage());
switch (selectionMode) {
case ListView.CHOICE_MODE_NONE:
holder.Checkbox.setVisibility(InertCheckBox.GONE);
holder.listStatusIndicatorImage.setVisibility(ImageView.VISIBLE);
holder.listStatusIndicatorImage.setImageBitmap((Bitmap) item.getListIndicatorImage());
break;
//case ListView.CHOICE_MODE_SINGLE: case ListView.CHOICE_MODE_MULTIPLE:
default:
holder.listStatusIndicatorImage.setVisibility(ImageView.GONE);
holder.Checkbox.setVisibility(InertCheckBox.VISIBLE);
holder.Checkbox.setButtonDrawable(R.drawable.checkbox);
holder.Checkbox.setChecked(isChecked);
break;
}
return convertView;
}
@Override
public long getItemId(int position) {
return getItem(position).getId();
}
@Override
public boolean hasStableIds() {
return true;
}
和 Item Class - 上半部分;
public class Item implements Comparable<Item> {
private long id;
private String title;
private String description;
private String session_count;
private Bitmap listImage;
private Bitmap statusImage;
public Item(long id, String title, String description, String session_count, Bitmap listImage, Bitmap statusImage) {
super();
this.id = id;
this.title = title;
this.description = description;
this.session_count = session_count;
this.listImage = listImage;
this.statusImage = statusImage;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
这是我的调试日志跟踪项目删除的视觉效果
07-23 22:59:14.910: D/drp(19104): Adapter Count is: 51
07-23 22:59:14.910: D/drp(19104): removing : 50 of 4-3 - Title: Test 50 - testing
07-23 22:59:14.910: D/drp(19104): removing : 49 of 4-2 - Title: Test 49 - testing
07-23 22:59:14.910: D/drp(19104): removing : 48 of 4-1 - Title: Test 48 - testing
如果我再次注释掉“mMyListViewAdapter.remove(item);” MainActivity 中的行没有崩溃,日志似乎表明它按预期工作。任何人都可以看到导致我的索引越界异常的错误吗?
此外,我正在使用 SDK 4.0.4 API 15。
非常感谢,
保罗。
加法——完整的日志输出
07-25 00:21:53.235: D/AbsListView(25952): Get MotionRecognitionManager
07-25 00:21:53.270: D/dalvikvm(25952): GC_CONCURRENT freed 89K, 3% free 13027K/13383K, paused 1ms+2ms
07-25 00:21:53.430: D/dalvikvm(25952): GC_CONCURRENT freed 207K, 4% free 13232K/13703K, paused 3ms+2ms
07-25 00:21:53.630: D/CLIPBOARD(25952): Hide Clipboard dialog at Starting input: finished by someone else... !
07-25 00:21:54.930: D/dalvikvm(25952): GC_FOR_ALLOC freed 189K, 4% free 13331K/13767K, paused 10ms
07-25 00:21:54.930: I/dalvikvm-heap(25952): Grow heap (frag case) to 13.610MB for 408976-byte allocation
07-25 00:21:54.940: D/dalvikvm(25952): GC_FOR_ALLOC freed 6K, 4% free 13724K/14215K, paused 9ms
07-25 00:21:54.950: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 13724K/14215K, paused 9ms
07-25 00:21:54.950: I/dalvikvm-heap(25952): Grow heap (frag case) to 13.994MB for 408976-byte allocation
07-25 00:21:54.960: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 14124K/14663K, paused 9ms
07-25 00:21:54.970: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 14124K/14663K, paused 9ms
07-25 00:21:54.975: I/dalvikvm-heap(25952): Grow heap (frag case) to 14.384MB for 408976-byte allocation
07-25 00:21:54.995: D/dalvikvm(25952): GC_CONCURRENT freed 0K, 4% free 14523K/15111K, paused 1ms+1ms
07-25 00:21:55.005: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 14523K/15111K, paused 9ms
07-25 00:21:55.005: I/dalvikvm-heap(25952): Grow heap (frag case) to 14.774MB for 408976-byte allocation
07-25 00:21:55.020: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 5% free 14923K/15559K, paused 9ms
07-25 00:21:55.030: D/dalvikvm(25952): GC_FOR_ALLOC freed <1K, 5% free 14923K/15559K, paused 9ms
07-25 00:21:55.030: I/dalvikvm-heap(25952): Grow heap (frag case) to 15.165MB for 408976-byte allocation
07-25 00:21:55.040: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 5% free 15322K/16007K, paused 10ms
07-25 00:21:55.055: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 5% free 15722K/16455K, paused 9ms
07-25 00:21:55.110: D/dalvikvm(25952): GC_FOR_ALLOC freed 157K, 5% free 16145K/16903K, paused 9ms
07-25 00:21:56.565: E/SKIA(25952): FimgApiStretch:stretch failed
07-25 00:21:56.690: E/SKIA(25952): FimgApiStretch:stretch failed
07-25 00:21:56.710: E/SKIA(25952): FimgApiStretch:stretch failed
07-25 00:22:00.545: D/drp(25952): Adapter Count is: 51
07-25 00:22:00.545: D/drp(25952): removing : 49 of 2-2 - Title: Test 49 - testing
07-25 00:22:00.545: D/drp(25952): removing : 48 of 2-1 - Title: Test 48 - testing
07-25 00:22:00.545: D/drp(25952): removing : 47 of 2-0 - Title: Test 47 - testing
07-25 00:22:00.550: D/AndroidRuntime(25952): Shutting down VM
07-25 00:22:00.550: W/dalvikvm(25952): threadid=1: thread exiting with uncaught exception (group=0x40c6f1f8)
07-25 00:22:00.560: E/AndroidRuntime(25952): FATAL EXCEPTION: main
07-25 00:22:00.560: E/AndroidRuntime(25952): java.lang.IndexOutOfBoundsException: Invalid index 48, size is 48
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.util.ArrayList.get(ArrayList.java:304)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:337)
07-25 00:22:00.560: E/AndroidRuntime(25952): at au.drp.mylistview.MyListViewAdapter.getItemId(MyListViewAdapter.java:107)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.AbsListView.confirmCheckedPositionsById(AbsListView.java:5956)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.AbsListView.handleDataChanged(AbsListView.java:5999)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.ListView.layoutChildren(ListView.java:1535)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.AbsListView.onLayout(AbsListView.java:2254)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.RelativeLayout.onLayout(RelativeLayout.java:925)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1644)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1502)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.LinearLayout.onLayout(LinearLayout.java:1415)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1721)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2678)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.os.Handler.dispatchMessage(Handler.java:99)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.os.Looper.loop(Looper.java:137)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.app.ActivityThread.main(ActivityThread.java:4514)
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.lang.reflect.Method.invokeNative(Native Method)
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.lang.reflect.Method.invoke(Method.java:511)
07-25 00:22:00.560: E/AndroidRuntime(25952): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
07-25 00:22:00.560: E/AndroidRuntime(25952): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
最佳答案
AbsListView 中似乎存在错误导致这个问题。 AbsListView 的任何子类都可能发生这种情况,包括 ListView 和 GridView。
在单选和多选模式下,ListView 通过验证 confirmCheckedPositionsById 中的选中项集来响应对其适配器的 。由于此时已从数据集中删除了所选项目,因此适配器将抛出异常。值得注意的是,仅当适配器的 notifyDataSetChanged() 调用()hasStableIds() 方法返回 true 时才会出现此问题。
笼统地说,这是相关路径:
ListView 更新其选定项目的列表notifyDataSetChanged(),它会通知其观察者数据集已更改。 ListView 是这些观察者之一。ListView 时,它会看到适配器的通知并调用 handleDataChanged()。此时,ListView 仍然认为我们现在删除的项目被选中并且在数据集中。handleDataChanged() 方法调用 confirmCheckedPositionsById(),后者会尝试使用陈旧位置在适配器上调用 getItemId() .如果被删除的项目恰好在列表的末尾附近,这个位置很可能超出数组范围,适配器将抛出 IndexOutOfBoundsException。两种可能的解决方法如下:
如其他答案中所述,每次数据集更改时创建一个新适配器。除非手动保存和恢复,否则这会导致丢失当前滚动位置的不幸影响。
在调用 notifyDataSetChanged 之前,通过在 在适配器上。所选项目无论如何都会被删除,因此丢失当前选择状态不太可能成为问题。此方法将保留滚动位置,并应防止在更新列表时出现闪烁。ListView(或 GridView)上调用 clearChoices() 来清除所选项目()
关于Android - 自定义 ListView 适配器 - 多选删除 - Indexoutofbounds - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11613517/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢