我正在使用列表视图来呈现类似网格视图的活动。有一个 OutOfBoundsException。这是日志。
03-21 11:47:13.106: E/AndroidRuntime(597): FATAL EXCEPTION: main
03-21 11:47:13.106: E/AndroidRuntime(597): java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1
03-21 11:47:13.106: E/AndroidRuntime(597): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
03-21 11:47:13.106: E/AndroidRuntime(597): at java.util.ArrayList.get(ArrayList.java:304)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:225)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.AbsListView.obtainView(AbsListView.java:2022)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.ListView.measureHeightOfChildren(ListView.java:1244)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.ListView.onMeasure(ListView.java:1155)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1369)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.LinearLayout.measureVertical(LinearLayout.java:660)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.LinearLayout.onMeasure(LinearLayout.java:553)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.RelativeLayout.measureChild(RelativeLayout.java:579)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:392)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1369)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.LinearLayout.measureVertical(LinearLayout.java:660)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.LinearLayout.onMeasure(LinearLayout.java:553)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
03-21 11:47:13.106: E/AndroidRuntime(597): at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2265)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1074)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2462)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.os.Handler.dispatchMessage(Handler.java:99)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.os.Looper.loop(Looper.java:137)
03-21 11:47:13.106: E/AndroidRuntime(597): at android.app.ActivityThread.main(ActivityThread.java:4486)
03-21 11:47:13.106: E/AndroidRuntime(597): at java.lang.reflect.Method.invokeNative(Native Method)
03-21 11:47:13.106: E/AndroidRuntime(597): at java.lang.reflect.Method.invoke(Method.java:511)
03-21 11:47:13.106: E/AndroidRuntime(597): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-21 11:47:13.106: E/AndroidRuntime(597): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-21 11:47:13.106: E/AndroidRuntime(597): at dalvik.system.NativeStart.main(Native Method)
我的 ListToGridAdapter 如下:
public class ListToGridAdapter extends BaseAdapter implements OnClickListener, OnLongClickListener {
/**
* The wrapper content --> adapter
*/
private SimpleAdapter mAdapter = null;
/**
* The number columns
*/
private int mColumns = 1;
/**
* The real onItemClickListener
*/
private OnGridItemClickListener mGridListener;
/**
* The real onItemLongClickListener
*/
private OnGridItemLongClickListener mGridLongClickListener;
/**
* The Context Object
*/
private Context mContext;
private int sidebarPixals = 0;
private int sideBlankPixals = 0;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (mColumns == 1) {
View child = mAdapter.getView(position, convertView, parent);
setOnItemClickListenerIfNeed(child, position, position);
setOnItemLongClickListenerIfNeed(child, position, position);
// no need
return child;
}
return bindGridView(position, convertView, parent);
}
protected View bindGridView(int position, View convertView, ViewGroup parent) {
ViewGroup root = null;
if (convertView == null || !(convertView instanceof ViewGroup)) {
root = createRoot();
root.setClickable(false);
root.setFocusable(false);
} else {
root = (ViewGroup) convertView;
}
// columns = 3
// pos --> real pos
// 0 --> 0 1 2
// 1 --> 3 4 5
// 2 --> 6 7 8
// so do this
return bindView(root, position);
}
protected ViewGroup bindView(ViewGroup root, int pos) {
final int count = mAdapter.getCount();
final int childCount = root.getChildCount();
for (int i = 0; i < mColumns; i++) {
// real position
int index = mColumns * pos + i;
// 不足一行时,直接返回现有状态
if (index == count) {
// fix bug : root是有可能是系统缓存的root,这里直接返回root将导致如果此行数量
// 不够columns,就会使用缓存的root里的child,为了避免这个问题,必须
// 将缓存的child移除。
removeCacheChild(root, index);
break;
} else if (index > count) {
throw new UnknownError("unknowError");
}
View child = mAdapter.getView(index, root.getChildAt(i), root);
setOnItemLongClickListenerIfNeed(child, pos, index);
setOnItemClickListenerIfNeed(child, pos, index);
if (childCount == mColumns) {
// root已经包含了Item,就没有必要继续添加了。
continue;
} else {
if (i == 0 && childCount != 0) {
// 如果root已经包含item,但是并不全,这里就移除重新添加
// FIXME 也许还有更好的方案
root.removeAllViews();
}
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
// LinearLayout.LayoutParams.WRAP_CONTENT,
(mContext.getResources().getDisplayMetrics().widthPixels - sidebarPixals - sideBlankPixals)
/ mColumns,
LinearLayout.LayoutParams.WRAP_CONTENT);
child.setFocusable(true);
child.setClickable(true);
if (child instanceof ViewGroup) {
((ViewGroup) child)
.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
root.addView(child, lp);
}
}
return root;
}
/**
* remove child view in cache of root
*/
private void removeCacheChild(ViewGroup root, int index) {
int realColumns = (index - 1) % mColumns;
int moveCount = (mColumns - 1) - realColumns;
for (int i = 0; i < moveCount; i++) {
final View child = root.getChildAt((mColumns - 1 - i));
if (child != null) {
root.removeView(child);
}
}
}
/**
* create root for item of ListView
*/
protected ViewGroup createRoot() {
LinearLayout root = new LinearLayout(mContext);
root.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
root.setLayoutParams(lp);
return root;
}
private boolean setOnItemClickListenerIfNeed(View child, int pos,
int realPos) {
if (mGridListener == null) {
return false;
}
child.setOnClickListener(this);
child.setTag(R.id.pos, pos);
child.setTag(R.id.realPos, realPos);
return true;
}
private boolean setOnItemLongClickListenerIfNeed(View child, int pos,
int realPos) {
if (mGridLongClickListener == null) {
return false;
}
child.setOnLongClickListener(this);
child.setTag(R.id.pos, pos);
child.setTag(R.id.realPos, realPos);
return true;
}
public void setOnItemClickListener(OnGridItemClickListener listener) {
this.mGridListener = listener;
}
public void setOnItemLongClickListener(OnGridItemLongClickListener listener){
this.mGridLongClickListener = listener;
}
public void setNumColumns(int columns) {
this.mColumns = columns;
}
public int getNumColumns() {
return mColumns;
}
public ListToGridAdapter(Context context, SimpleAdapter adapter) {
this.mContext = context;
this.mAdapter = adapter;
int model = YoutubeAPI.getKindleFireModel();
if (model == 1){
sideBlankPixals = 10 * 2;
sidebarPixals = 0;
} else if (model == 2){
sideBlankPixals = 10 * 2;
sidebarPixals = 60;
} else if (model == 3){
sideBlankPixals = (int)(10 * 2 * 1.5);
sidebarPixals = 78;
} else if (model == 4){
sideBlankPixals = (int)(10 * 2 * 1.5);
sidebarPixals = 90;
}
}
@Override
public int getCount() {
int count = (int) Math.ceil(mAdapter.getCount() / (double) mColumns);
return count;
}
@Override
public Object getItem(int position) {
return mAdapter.getItem(position);
}
@Override
public long getItemId(int position) {
return mAdapter.getItemId(position);
}
@Override
public boolean hasStableIds() {
return mAdapter.hasStableIds();
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
mAdapter.registerDataSetObserver(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
mAdapter.unregisterDataSetObserver(observer);
}
@Override
public boolean areAllItemsEnabled() {
return mAdapter.areAllItemsEnabled();
}
@Override
public boolean isEnabled(int position) {
return mAdapter.isEnabled(position);
}
@Override
public int getItemViewType(int position) {
return mAdapter.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
return mAdapter.getViewTypeCount();
}
@Override
public boolean isEmpty() {
return mAdapter.isEmpty();
}
public ListAdapter getWrappedAdapter() {
return mAdapter;
}
public static interface OnGridItemClickListener {
public void onItemClick(int pos, int realPos);
}
public static interface OnGridItemLongClickListener{
public void onItemLongClick(int pos, int realPos);
}
@Override
public void onClick(View v) {
if (mGridListener == null) {
// no need to feedback
}
int pos = (Integer) v.getTag(R.id.pos);
int realPos = (Integer) v.getTag(R.id.realPos);
mGridListener.onItemClick(pos, realPos);
}
@Override
public boolean onLongClick(View v) {
if (mGridLongClickListener == null) {
// no need to feedback
}
int pos = (Integer) v.getTag(R.id.pos);
int realPos = (Integer) v.getTag(R.id.realPos);
mGridLongClickListener.onItemLongClick(pos, realPos);
return true;
}
}
在活动中,
ListToGridAdapter mAdapter = new ListToGridAdapter(this, mVideoGridviewAdapter);
mAdapter.setNumColumns(3);
pullToRefreshListview.setAdapter(mAdapter);
mVideoGridviewAdapter 是一个 simpleAdapter。
哪里有问题?似乎是列表视图的页脚,但我不知道如何修复它。
==== 编辑 =====
在活动中,我添加了一些 AsyncTask 来刷新列表视图。在onPostExecute
我将一些项目添加到列表视图中,使列表视图更长,并将列表视图的页脚视图从 更改View.VISIBLE
为View.INVISIBLE
,这有关系吗?