从Android Studio中的SQLite数据库列创建字符串数组

时间:2017-07-31 17:44:49

标签: arrays string listview android-sqlite

我创建了一个带有SQLite数据库和ListView的应用程序,我想用数据库填充它。为此,我编写了一个名为HomeListAdapter的适配器类。这个类需要4个字符串数组作为输入,这就是我的问题所在。起初,我只是使用随机字符串数组来填充ListView,方法是自己输入,例如:

String[] homelist_name_short = {
  "Flower", "Bush", "Tree"};

String[] homelist_name_long = {
  "Red rose", "Berry bush", "Oak"};

String[] homelist_date = {
  "20-9-2017", "11-10-2017", "12-10-2017"};

String[] homelist_price = {
  "€1.50", "€2.48", "€0.68"};

现在我希望将其自动放入listview,为此我已经编写了可以在下面看到的代码..

我创建了一个名为Home的类:

public class Home {
private String mShortHomeName;
private String mLongHomeName;
private String mHomeDate;
private String mHomePrice;

public Home(String ShortName, String LongName, String Date, String Price) {
    this.mShortHomeName = ShortName;
    this.mLongHomeName = LongName;
    this.mHomeDate = Date;
    this.mHomePrice = Price;
}

public String getShortName() {
    return this.mShortHomeName;
}

public String getLongName() {
    return this.mLongHomeName;
}

public String getDate() {
    return this.mHomeDate;
}

public String getPrice() {
    return  this.mHomePrice;
}
}

在我的DatabaseHelper中添加了以下内容:

public Cursor getAllHomesAsCursor() {
    SQLiteDatabase db = this.getWritableDatabase();
    String[] columns = {"rowid as _id","*"};
    return db.query(TABLE_NAME,columns,null,null,null,null,null);
}

包含我的listview的活动的以下内容:

DatabaseHelper db = new DatabaseHelper(getActivity());
    Cursor csr = db.getAllHomesAsCursor();
    HLAdapter adapter = new HLAdapter(getActivity(), csr);
    listView.setAdapter(adapter);

HLAdapter如下所示:

public class HLAdapter extends CursorAdapter {

public HLAdapter(Context context, Cursor cursor) {
    super(context, cursor, 0);
}

@Override
public View newView(Context context, Cursor csr, ViewGroup parent) {
    return LayoutInflater.from(context).inflate(
            R.layout.homelist_listview_layout,
            parent,
            false
    );
}

@Override
public void bindView(View view, Context context, Cursor csr) {
    TextView sname = (TextView) view.findViewById(R.id.homelist_name_short);
    TextView lname = (TextView) view.findViewById(R.id.homelist_name_long);
    TextView date = (TextView) view.findViewById(R.id.homelist_date);
    TextView price = (TextView) view.findViewById(R.id.homelist_price);

    sname.setText(csr.getString(csr.getColumnIndex("name_short")));
    lname.setText(csr.getString(csr.getColumnIndex("name_long")));
    date.setText(csr.getString(csr.getColumnIndex("date")));
    price.setText(csr.getString(csr.getColumnIndex("price")));
}
}

我的DatabaseHelper类如下所示:

public class DatabaseHelper extends SQLiteOpenHelper{

public static final String DATABASE_NAME = "Main.db";
public static final String TABLE_NAME = "current_table";
public static final String COL_1 = "name_short";
public static final String COL_2 = "name_long";
public static final String COL_3 = "date";
public static final String COL_4 = "price";

public DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, 1);
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL("create table " + TABLE_NAME + " (name_short TEXT,name_long TEXT, due_date TEXT, price TEXT) ");
}

@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
    onCreate(db);
}

public Cursor getAllHomesAsCursor() {
    SQLiteDatabase db = this.getWritableDatabase();
    String[] columns = {"rowid as _id","*"};
    return db.query(TABLE_NAME,columns,null,null,null,null,null);
}

public boolean insertData(String name_short, String name_long, String due_date, String price) {
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues contentValues = new ContentValues();
    contentValues.put(COL_1,name_short);
    contentValues.put(COL_2,name_long);
    contentValues.put(COL_3,due_date);
    contentValues.put(COL_4,price);
    long result = db.insert(TABLE_NAME,null,contentValues);
    if(result == -1)
        return false;
    else
        return true;
}

public void deleteAllData() {
    SQLiteDatabase db = this.getWritableDatabase();
    db.execSQL("DELETE FROM " + TABLE_NAME);
}

public Cursor getAllData() {
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor res = db.rawQuery("SELECT * FROM " + TABLE_NAME ,null);
    return res;
}

public Cursor getSpecifiedColumnData(String column) {
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor res = db.rawQuery("SELECT column FROM " + TABLE_NAME,null);
    return res;
}
}

我认为我的代码应该运行正常,但是当我运行应用程序时。它会立即关闭。你能告诉我这是什么问题吗?

1 个答案:

答案 0 :(得分:0)

我认为问题在于您需要将4个String数组传递给适配器,因此,如上所述,您需要为每种类型提供唯一的getAllData等效项。

然而,考虑到房屋名称较短,名称,日期和价格较长,更好的方法是将所有这些属性视为对象,从而创建一个类。然后,您可以创建一个List not of String对象,但作为House对象列表,您可以一次性获取所有这些对象等。

所以(P.S.为了我的理智,我将SO4522191合并到下面,所以我可以保留一些代码跟踪): -

1)创建您的Home对象以保存房屋的所有值/属性: -

1-a)创建一个与您的主页名称相同的文件,它将成为一个java类文件。

在这种情况下,我称之为 SO45422191Home ,代码可以是: -

public class SO45422191Home {
    private String mShortHomeName;
    private String mLongHomeName;
    private String mHomeDate;
    private String mHomePrice;

    public SO45422191Home(String ShortName, String LongName, String Date, String Price) {
        this.mShortHomeName = ShortName;
        this.mLongHomeName = LongName;
        this.mHomeDate = Date;
        this.mHomePrice = Price;
    }

    public String getShortName() {
        return this.mShortHomeName;
    }

    public String getLongName() {
        return this.mLongHomeName;
    }

    public String getDate() {
        return this.mHomeDate;
    }

    public String getPrice() {
        return  this.mHomePrice;
    }
}
  

解释

     

使用上面我们可以在其他地方的代码中创建一个SO45422191Home对象,例如在你的活动中,通过使用某些东西   比如SO45422191Home Myhome = new SO45422191Home("Flower","Red Rose","20-9-2017","1.50");

     

使用MyHome对象,您可以提取属性,例如   MyHome.getPrice()将返回值为 1.50 的字符串。   与其他属性相似。

     

您可以创建一个对象数组,例如SO45422191Home[] homes = new SO45422191Home[3];将创建一个3(空)SO45422191Home的数组   对象。我们可以使用homes[0] = new SO45422191Home("Bush","Cherry","11-10-2017","2.48");

设置数组的第一个元素

2)创建一种从数据库中获取 SO45422191Home 对象数组的方法。

这里有一些代码: -

public List<SO45422191Home> getAllHomes() {
    List<SO45422191Home> rv = new ArrayList<>();
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor csr = db.query(HOMETABLE,null,null,null,null,null,null);
    while (csr.moveToNext()) {
        SO45422191Home h = new SO45422191Home(
                csr.getString(csr.getColumnIndex(SHORTHOMENAME)),
                csr.getString(csr.getColumnIndex(LONGHOMENAME)),
                csr.getString(csr.getColumnIndex(HOMEDATE)),
                csr.getString(csr.getColumnIndex(HOMEPRICE))
        );
        rv.add(h);
    }
    csr.close();
    return rv;
}
  

说明您使用了List并在列表中添加了元素,List类似但是对于SO45422191Home对象而不是

     

比String对象。

     

使用SQLiteDatabase db = this.getWritableDatabase();打开数据库(如果尚未打开)。

     

将所有行提取到游标中。

     

一次遍历每行的光标。

     

对于每一行,通过从光标获取相应数据来创建 SO45422191Home 对象

     

请注意,使用了csr.getColumnIndex(columnname)   而不是对列的索引/偏移进行硬编码,这样做可以减少   错误的可能性以及减少的开销应该是变化的   应用的)。

     

新对象已添加到列表中。

     

显然必须调整列名,您可能还想在返回前添加db.close()

3)修改您的适配器以获取和使用单个对象列表而不是4列表。

这是列表使用的示例适配器(请注意, R.layout.homeentry 是ListView中每个条目使用的布局),布局如下所示>光标适配器: -

public class AdapterHomeList2 extends ArrayAdapter {

    List<SO45422191Home> homes;
    LayoutInflater lInflater;

    public AdapterHomeList2(Context context, List<SO45422191Home> homes) {
        super(context,R.layout.homeentry, homes);
        lInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.homes = homes;
    }


    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {

        View view = convertView;
        if (view == null) {
            view = lInflater.inflate(R.layout.homeentry, parent, false);
        }

        TextView sname = (TextView) view.findViewById(R.id.shortname);
        TextView lname = (TextView) view.findViewById(R.id.longname);
        TextView date = (TextView) view.findViewById(R.id.date);
        TextView price = (TextView) view.findViewById(R.id.price);

        sname.setText(homes.get(position).getShortName());
        lname.setText(homes.get(position).getLongName());
        date.setText(homes.get(position).getDate());
        price.setText(homes.get(position).getPrice());
        return view;
    }
}

这是 ArrayList 的代码: -

public class AdapterHomeList3 extends ArrayAdapter {

    ArrayList<SO45422191Home> homes;
    LayoutInflater lInflater;

    public AdapterHomeList3(Context context, ArrayList<SO45422191Home> homes) {
        super(context,R.layout.homeentry, homes);
        lInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.homes = homes;
    }


    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {

        View view = convertView;
        if (view == null) {
            view = lInflater.inflate(R.layout.homeentry, parent, false);
        }

        TextView sname = (TextView) view.findViewById(R.id.shortname);
        TextView lname = (TextView) view.findViewById(R.id.longname);
        TextView date = (TextView) view.findViewById(R.id.date);
        TextView price = (TextView) view.findViewById(R.id.price);

        sname.setText(homes.get(position).getShortName());
        lname.setText(homes.get(position).getLongName());
        date.setText(homes.get(position).getDate());
        price.setText(homes.get(position).getPrice());
        return view;
    }
}

使用CursorAdapter

1)添加一个新方法来提取包含所有行的游标(注意!对于游标适配器,需要一行名为_id的行

public Cursor getAllHomesAsCursor() {
    SQLiteDatabase db = this.getWritableDatabase();
    String[] columns = {"rowid as _id","*"};
    return db.query(HOMETABLE,columns,null,null,null,null,null);
}
  

请注意!代替所有列,即编码null作为第二参数   要查询&#39; (没有得到隐藏的rowid列(假设   没有ROWID还没有使用过)),会得到rowid(unqiue)   行标识符)并将此 AS _id命名为套件游标适配器   因此"rowid as _id",以下 * 作为第二个元素   columns数组表示所有行(将null指定为第二个参数   结果为SELECT * .....)。

     

否则它非常简单。注意您不能关闭数据库,   否则你无法访问光标。

2)您将需要列表中每个项目的布局,就像您对自定义数组适配器一样,它可以是相同的,即根据使用的适配器没有区别。例如我创建了: -

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/shortname"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/longname"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/date"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/price"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
</LinearLayout>

3)将Cursor Adpater创建为类文件,非常类似于数组适配器。

public class AdapterHomeList extends CursorAdapter {

    public AdapterHomeList(Context context, Cursor cursor) {
        super(context, cursor,0);
    }

    @Override
    public View newView(Context context, Cursor csr, ViewGroup parent) {
        return LayoutInflater.from(context).inflate(
                R.layout.homeentry, //<< layout for each list item
                parent,
                false
        );
    }

    @Override
    public void bindView(View view, Context context, Cursor csr) {

        TextView sname = (TextView) view.findViewById(R.id.shortname);
        TextView lname = (TextView) view.findViewById(R.id.longname);
        TextView date = (TextView) view.findViewById(R.id.date);
        TextView price = (TextView) view.findViewById(R.id.price);

        sname.setText(csr.getString(csr.getColumnIndex(SO45422191.SHORTHOMENAME)));
        lname.setText(csr.getString(csr.getColumnIndex(SO45422191.LONGHOMENAME)));
        date.setText(csr.getString(csr.getColumnIndex(SO45422191.HOMEDATE)));
        price.setText(csr.getString(csr.getColumnIndex(SO45422191.HOMEPRICE)));
    }
}
  

请注意! R.layout.homeentry 是列表条目的布局   并且id来自此。

4)从相应的活动中,获取光标,获取适配器的实例并设置ListView以使用适配器。

e.g: -

        Cursor csr = dbhlp.getAllHomesAsCursor();
        AdapterHomeList ahl = new AdapterHomeList(this,csr);
        ListView hl = (ListView) this.findViewById(R.id.homelist);
        hl.setAdapter(ahl);

结果: -

enter image description here

使用cursor.getColumnIndex()

getColumnIndex

  

int getColumnIndex (String columnName)

     

返回给定列名的从零开始的索引,如果是,则返回-1   专栏不存在。如果您希望列存在使用   相反,getColumnIndexOrThrow(String)会使错误更多   清楚。

SQLiteCursor

使用getColumnIndex而不是指定索引,无需手动确定列偏移。

例如,有一个名为项目的表格,其中包含3列,名称为名称日期价格< / strong>: -

使用相当于SELECT * FROM items的查询,查询将返回包含3列的游标,名称日期价格< /强>

  • 名称的偏移量为0。
  • 日期的偏移量为1。
  • 价格的偏移量为2。

要从光标中提取日期,您可以编码cursor.getString(1);

但是,如果您要根据SELECT date, price, name FROM items进行查询,则偏移量为: -

  • 名称的偏移量为2。
  • 日期的偏移量为0。
  • 价格的偏移量为1。

在这种情况下,您必须编码cursor.getString(0);以提取日期

可能很容易无意中编码错误的偏移量,尤其是在使用较大的表或连接表或引入生成的列时。

在两种情况下都可以使用cursor.getString(cursor.getColumnIndex("date"));,因为它会在第一种情况下返回1,在第二种情况下返回0。

以上,作为示例,sname.setText(csr.getString(csr.getColumnIndex(SO45422191.SHORTHOMENAME)));已被编码。

Home.SHORTHOMENAME 数据库助手中定义的类变量(即 SO45422191 是DatabaseHelper类, SHORTHOMENAME 是类变量),相当于相应列的列名,可以从数据库助手代码提取中看到: -

public class SO45422191 extends SQLiteOpenHelper {

    public static final String DBNAME = "SO45422191";
    public static final String HOMETABLE = "homes";

    public static final String SHORTHOMENAME = "shorthomename";
    public static final String LONGHOMENAME = "longhomename";
    public static final String HOMEDATE = "homedate";
    public static final String HOMEPRICE = "homeprice";

    // constructor
    public SO45422191(Context context) {

        super(context, DBNAME  , null , 1);
    }


    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table " +  HOMETABLE +
                "(" +
                        SHORTHOMENAME + " TEXT, " +
                LONGHOMENAME + " TEXT, " +
                HOMEDATE + " TEXT, " +
                HOMEPRICE + ")");