ListView/adapter 抛出 IndexOutOfBound

ListView/adapter throwing IndexOutOfBound

我有一个 getCount() 为 7 的列表视图。我希望​​显示所有 7 个项目,无论我的数据库中是否有任何数据可用于填充它们。如果没有可用数据,则项目应为空白并带有预定文本。

如果我事先没有硬编码 7 个数据库条目以进入 7 个视图,那么当 运行 应用程序由于无法相应地填充 7 个项目时,我会收到 indexoutofbound 异常。当调用方法 Meal currentItem = getItem(position); 并触发 public Meal getItem(int position).

时,这发生在 ListMealsAdapter.java 中

我正在寻找可用于我的 listview/adapter 的条件语句,它可以处理空数据库,以便索引不会越界。另外,BaseAdapter 是否适合我想做的事情?

MainActivity.java

public class MainActivity extends BaseActivity {
public static final String TAG = "MainActivity";

private ListView mListviewMeals;
private MealDAO mMealDao;
private List<Meal> mListMeals;
private ListMealsAdapter mAdapter;
private SQLiteDatabase mDatabase;
DatabaseHelper mDbHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    activateToolbar(1);

    // initialize views
    initViews();

    // fill the dailyListView
    mMealDao = new MealDAO(this);
    mListMeals = mMealDao.getAllMeals();
    mAdapter = new ListMealsAdapter(this, mListMeals, MainActivity.this);
    mListviewMeals.setAdapter(mAdapter);
}

private void initViews() {
    this.mListviewMeals = (ListView) findViewById(R.id.view_daily_list);
}

ListMealsAdapter.java

public class ListMealsAdapter extends BaseAdapter {
    public static final String TAG = "ListMealsAdapter";

    Activity mActivity;
    private List<Meal> mItems;
    private LayoutInflater mInflater;

    public ListMealsAdapter(Context context, List<Meal> listMeals, Activity activity) {
        super();
        mActivity = activity;
        this.setItems(listMeals);
        this.mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return 7;
    }

    @Override
    public Meal getItem(int position) {
        return (getItems() != null && !getItems().isEmpty()) ? getItems().get(position) : null;
    }

    @Override
    public long getItemId(int position) {
        return (getItems() != null && !getItems().isEmpty()) ? getItems().get(position).getId() : position;
    }

    @Override
    public View getView(int position, final View convertView, final ViewGroup parent) {
        View v = convertView;
        final ViewHolder holder;
        if (v == null) {
            v = mInflater.inflate(R.layout.list_item_daily, parent, false);
            holder = new ViewHolder();
            holder.txtDescription = (TextView) v.findViewById(R.id.txtBreakfast);
            v.setTag(holder);
        } else {
            holder = (ViewHolder) v.getTag();
        }

        // fill row data
        Meal currentItem = getItem(position);
        if (currentItem != null) {
            holder.txtDescription.setText(currentItem.getDescription());
        }

        return v;
    }

    public List<Meal> getItems() {
        return mItems;
    }

    public void setItems(List<Meal> mItems) {
        this.mItems = mItems;
    }

    class ViewHolder {
        TextView txtDescription;
    }
}

Meal.java

public class Meal implements Serializable {
    public static final String TAG = "Meal";
    private static final long serialVersionUID = -7406082437623008161L;

    private long mId;
    private int mType;
    private String mDescription;

    public Meal() {
    }

    public Meal(int type, String description) {
        this.mType = type;
        this.mDescription = description;
    }

    public long getId() {
        return mId;
    }

    public void setId(long mId) {
        this.mId = mId;
    }

    public int getType() {
        return mType;
    }

    public void setType(int mType) {
        this.mType = mType;
    }

    public String getDescription() {
        return mDescription;
    }

    public void setDescription(String mDescription) {
        this.mDescription = mDescription;
    }
}

MealDAO.java

public class MealDAO {
    public static final String TAG = "MealDAO";

    private SQLiteDatabase mDatabase;
    private DatabaseHelper mDbHelper;
    private Context mContext;
    private String[] mAllColumns = { DatabaseHelper.COLUMN_MEAL_ID,
            DatabaseHelper.COLUMN_MEAL_TYPE, DatabaseHelper.COLUMN_MEAL_DESCRIPTION};

    public MealDAO(Context context) {
        this.mContext = context;
        mDbHelper = new DatabaseHelper(context);
        // open the database
        try {
            open();
        } catch (SQLException e) {
            Log.e(TAG, "SQLException on opening database " + e.getMessage());
            e.printStackTrace();
        }
    }

    public void open() throws SQLException {
        mDatabase = mDbHelper.getWritableDatabase();
    }

    public void close() {
        mDbHelper.close();
    }

    public List<Meal> getAllMeals() {
        List<Meal> listMeals = new ArrayList<Meal>();

        Cursor query = mDatabase.rawQuery("SELECT * from meal", null);
        if(query.moveToFirst()) {
            do {

                // Cycle through all records
                Meal meal = cursorToMeal(query);
                listMeals.add(meal);
            } while(query.moveToNext());
        }

        return listMeals;
    }

    public Meal getMealById(long id) {
        Cursor cursor = mDatabase.query(DatabaseHelper.TABLE_MEALS, mAllColumns,
                DatabaseHelper.COLUMN_MEAL_ID + " = ?",
                new String[] { String.valueOf(id) }, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
        }

        Meal meal = cursorToMeal(cursor);
        return meal;
    }

    protected Meal cursorToMeal(Cursor cursor) {
        Meal meal = new Meal();
        meal.setId(cursor.getLong(0));
        meal.setType(cursor.getInt(1));
        meal.setDescription(cursor.getString(2));
        return meal;
    }
}

经过反复试验,我终于找到了可以接受的解决方案。我所做的是在我的数据库中添加一个默认行,用于我希望在事先没有输入任何数据时具有预定数据库条目的视图项。

然后我确保从索引 2 开始,确保索引 1 将保留为我的默认值。如果索引超出范围,则会捕获异常并将默认数据库条目添加到数组中。

public Meal getItem(int position) {
    Meal result;
    try {
        result = (getItems() != null && !getItems().isEmpty()) ? getItems().get(position) : null;
    } catch (Exception e) {
        Meal default = getItem(0);
        return default;
    }
    return result;
}

Meal currentItem = getItem(position + 1);
        if (currentItem != null) {
            holder.txtDescription.setText(currentItem.getDescription());
        }

自那以后,事情变得 运行 顺利。我希望这也可以帮助其他人。