首页 > 解决方案 > 使用 ListView 在下一个活动中显示数据库详细信息

问题描述

我是 Android Studio 的新手,

我已经有 3 列的数据库文件(ID、标题、详细信息)

我想从数据库创建一个包含“标题”的 ListView,当我单击其中一个标题时,它将前往下一个活动并显示我之前单击的标题中的“详细信息”。

数据库文件位于 assets 文件夹中。

我正在使用 Android Studio 最新版本,请帮助我获取 xml、java 和清单代码。谢谢你。

这是我的代码,我只是成功地在 ListView 中显示了“标题”列,其余的我不知道该怎么做。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    static final String DBNAME = "story.db";
    static final String DBASSETPATH = "databases/" + DBNAME;
    static final String DBTABLE = "table";
    static final String DBTITLE = "title";
    static final String IDCOLUMN = "_id";

    ListView mTableList;
    SQLiteDatabase mDB;
    SimpleCursorAdapter mSCA;
    Cursor mCsr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTableList = (ListView) this.findViewById(R.id.storylist);
        mDB = openStoryDB();
        if (mDB != null) {
            mCsr = mDB.query(DBTABLE,
                    new String[]{IDCOLUMN + " AS _id",
                            DBTITLE
                    },
                    null,null,null,null,null);
            mSCA = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,mCsr,
                    new String[]{DBTITLE},
                    new int[]{android.R.id.text1},0);
            mTableList.setAdapter(mSCA);

        } else {
            Toast.makeText(this,"Unable to open Database.",Toast.LENGTH_LONG);

    }


}

    private SQLiteDatabase openStoryDB() {
        String dbpath = this.getDatabasePath(DBNAME).getPath();
        if (this.getDatabasePath(DBNAME).exists()) {
            Log.d("OPENSTORYDB","Opening already existing Database");
            return SQLiteDatabase.openDatabase(dbpath,null,SQLiteDatabase.OPEN_READWRITE);
        }
        InputStream is;
        byte[] buffer;
        FileOutputStream db;
        try {
            is =  this.getAssets().open(DBASSETPATH);
            buffer = new byte[is.available()];
            is.read(buffer);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.d("OPENSTORYDB","Unable to locate or buffer input from assets " + DBASSETPATH);
            return null;
        }
        // Just in case the databases directory doesn't exist create it.
        File dbmkdir = (this.getDatabasePath(DBNAME)).getParentFile();
        dbmkdir.mkdirs();
        try {
            db = new FileOutputStream(this.getDatabasePath(DBNAME).getPath());
        } catch (Exception e) {
            e.printStackTrace();
            Log.d("OPENSTORYDB","Unable to create outputstream for DB at path " + dbpath);
            try {
                is.close();
            } catch (Exception e2) {
            }
            return null;
        }
        try {
            db.write(buffer);
            db.flush();
            db.close();
            is.close();
        } catch (Exception e) {
            Log.d("OPENSTORYDB","Failed to copy asset to DB");
            e.printStackTrace();
            return null;
        }
        return SQLiteDatabase.openDatabase(dbpath,null,SQLiteDatabase.OPEN_READWRITE);
    }
}

MainActivity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.book.story.MainActivity">


    <ListView
        android:id="@+id/storylist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>

</LinearLayout>

标签: androiddatabasesqlitelistviewandroid-sqlite

解决方案


你需要

  1. 将 ListView 添加到初始活动的适当布局中。
  2. 创建一个数据库助手类,它将:
    1. 检查数据库是否已经存在
    2. 如果数据库不存在,则从 assets 文件夹中复制数据库
    3. 根据需要提供访问数据的方法(在填充 Listview 的情况下,将需要一个方法来检索要列出的数据)
  3. 在初始活动中获取数据库助手类的实例
  4. 通过它的 id 获取 ListView。
  5. 为 ListView 实例化一个合适的适配器。
  6. 将 ListView 设置为使用适配器
  7. 将 onItemClick 侦听器添加到 ListView,它将从所选项目中提取足够的详细信息(id),使用详细信息设置 Intent extra(s),然后启动其他活动(然后可以从 Intent 中提取详细信息)。

例子

以下作为基于您的问题的示例。

数据库

名为mydb的数据库,因此是资产文件夹中名为mydb的文件,其中包含表mytable:-

在此处输入图像描述

布局

一个简单的布局,包括一个已被赋予 ID 的 Listview,已用于名为MainActivity的活动,ListView 的代码是:-

<ListView
    android:id="@+id/myListView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
</ListView>

数据库助手

数据库助手已创建为DBHelper.java。实例化时,它会检查数据库是否作为文件存在,如果不存在,则尝试从资产文件夹中复制数据库(如果失败,例如资产不存在,则会引发运行时异常)。然后打开数据库。有一个公共方法getAllFromMytable返回一个 Cursor ,其中包含 mytable 表中的所有行:-

public class DBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "mydb"; //<<<<<<<<<< Database file name including extension
    public static final int DBVERSION = 101;

    public static final String TBL_MYTABLE = "mytable"; //<<<<<<<<<< The table name
    public static final String COL_MYTABLE_ID = "id"; //<<<<<<<<<< The id column name
    public static final String COl_MYTABLE_TITLE = "title"; //<<<<<<<<<< The title column name
    public static final String COL_MYTABLE_DETAILS = "details"; //<<<<<<<<<< The details column name

    Context mContext;
    SQLiteDatabase mDB;


    public DBHelper(Context context) {
        super(context, DBNAME, null, DBVERSION);
        mContext = context;

        if(!ifDBExists()) {
            copyDatabaseFromAssetsFolder();
        }
        mDB = this.getWritableDatabase();

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        super.onDowngrade(db, oldVersion, newVersion);
    }

    public Cursor getAllFromMytable() {
        String[] columns = new String[]{"*, id AS " + BaseColumns._ID}; //<<<<<<<<<< need column named _id so generate it
        return  mDB.query(TBL_MYTABLE,columns,null,null,null,null,null);
    }

    private void copyDatabaseFromAssetsFolder() {

        int stage = 0, buffer_size = 4096, blocks_copied = 0, bytes_copied = 0;

        try {
            InputStream is = mContext.getAssets().open(DBNAME);
            stage++;
            OutputStream os =  new FileOutputStream(mContext.getDatabasePath(DBNAME));
            stage++;
            byte[] buffer = new byte[buffer_size];
            int length;
            while ((length = is.read(buffer))>0) {
                blocks_copied++;
                os.write(buffer, 0, length);
                bytes_copied += length;
            }
            os.flush();
            os.close();
            is.close();

        } catch (IOException e) {
            e.printStackTrace();
            String exception = "";

            switch (stage) {
                case 0:
                    exception = "Unable to open asset file " + DBNAME;
                    break;
                case 1:
                    exception = "Unable to open the Database file " + DBNAME + " for output.";
                    break;
                case 2:
                    exception = "Error whilst copying " + DBNAME +
                            " from the assets folder to " + mContext.getDatabasePath(DBNAME).toString() +
                            " - successfully copied " + String.valueOf(blocks_copied) + " blocks."
                    ;
            }
            throw  new RuntimeException(exception + " (see stack-trace above)");
        }
    }

    // Check if the Database exists
    private boolean ifDBExists() {
        File db = mContext.getDatabasePath(DBNAME);
        if (db.exists()) return true;
        if (!db.getParentFile().exists()) {
            db.getParentFile().mkdirs();
        }
        return false;
    }
}

主要活动

这进行了 4-7,除了不是开始另一个活动,而是通过 Toast 显示 ListView 中单击项目的详细信息:-

public class MainActivity extends AppCompatActivity {

    ListView mMyListView;
    DBHelper mDBHlpr;
    Cursor mCsr;
    SimpleCursorAdapter mSCA;
    Context mContext;

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

        mDBHlpr = new DBHelper(this); //<<<<<<<<<< Instantiate the DBHelper

        mMyListView = this.findViewById(R.id.myListView);
    }

    private void manageListView() {
        mCsr = mDBHlpr.getAllFromMytable(); //<<<<<<<<<< get the latest data from the database
        if (mSCA == null) {
            mSCA = new SimpleCursorAdapter(
                    this,
                    android.R.layout.simple_list_item_1,mCsr,
                    new String[]{DBHelper.COl_MYTABLE_TITLE},
                    new int[]{android.R.id.text1},
                    0
            );
            mMyListView.setAdapter(mSCA);
            mMyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    // Start the other activity here passing the id (sufficient to find the specififc row)via an intent extra

                    // Toast used as an example of extracting the respective data from the cursor
                    Toast.makeText(
                            mContext,
                            "You clicked on the row with an id of " + String.valueOf(id) +
                            " the Title is " + mCsr.getString(mCsr.getColumnIndex(DBHelper.COl_MYTABLE_TITLE)) +
                            " the Details are " + mCsr.getString(mCsr.getColumnIndex(DBHelper.COL_MYTABLE_DETAILS)) +
                            " the id column is " + String.valueOf(mCsr.getLong(mCsr.getColumnIndex(DBHelper.COL_MYTABLE_ID))),
                            Toast.LENGTH_SHORT
                    ).show();
                }
            });
        } else {
            mSCA.swapCursor(mCsr);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCsr.close(); //<<<<<<<<<< ensure that the cursor is closed when done with
    }

    @Override
    protected void onResume() {
        super.onResume();
        manageListView(); //<<<<<<<<<< refresh the listview
    }
}

笔记

  • 请参考可以通过搜索轻松获得的评论和/或适当的文档
  • ManageListView不会直接调用,因为onResume方法在活动启动时运行。

结果

Toast 的屏幕截图:-

在此处输入图像描述

额外的

将 id 传递给另一个活动,然后提取该活动中的详细信息列。

首先,在数据库助手类中增加一个新方法,允许详细信息列作为字符串返回,并根据id获取

例如,上面的 DBHelper.java 将添加以下内容:-

public String getDetailsFromId(long id) {
    String rv = "";
    String whereclause = COL_MYTABLE_ID + "=?";
    String[] whereargs = new String[]{String.valueOf(id)};
    Cursor csr = mDB.query(TBL_MYTABLE,null,whereclause,whereargs,null,null,null);
    if (csr.moveToFirst()) {
        rv = csr.getString(csr.getColumnIndex(COL_MYTABLE_DETAILS));
    }
    csr.close();
    return rv;
}

创建其他活动,确保它在清单中定义(使用 File/New/Activity 相应地修改清单)。

此活动可能类似于(这将根据用于启动活动的额外意图传递的 id 显示详细信息):-

public class OtherActivity extends AppCompatActivity {

    public static final String INTENTKEY_MYTABLEIDCOLUMNS = "ikey_mytableidcolumn";

    TextView mDetails;
    DBHelper mDBHlpr;

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

        mDetails = this.findViewById(R.id.mydetails);

        mDBHlpr = new DBHelper(this);

        long id = this.getIntent().getLongExtra(INTENTKEY_MYTABLEIDCOLUMNS,-1);
        mDetails.setText(mDBHlpr.getDetailsFromId(id));

    }
}

最后修改初始活动以实例化可用于启动其他活动的 Intent,然后将 id 作为附加项并最后启动其他活动,例如以下可以在上述活动中使用而不是(以及如果你想要)吐司:-

        mMyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // Start the other activity here passing the id (sufficient to find the specififc row)via an intent extra

                // Toast used as an example of extracting the respective data from the cursor
                /*
                Toast.makeText(
                        mContext,
                        "You clicked on the row with an id of " + String.valueOf(id) +
                        " the Title is " + mCsr.getString(mCsr.getColumnIndex(DBHelper.COl_MYTABLE_TITLE)) +
                        " the Details are " + mCsr.getString(mCsr.getColumnIndex(DBHelper.COL_MYTABLE_DETAILS)) +
                        " the id column is " + String.valueOf(mCsr.getLong(mCsr.getColumnIndex(DBHelper.COL_MYTABLE_ID))),
                        Toast.LENGTH_SHORT
                ).show();
                */

                Intent i = new Intent(mContext,OtherActivity.class);
                i.putExtra(OtherActivity.INTENTKEY_MYTABLEIDCOLUMNS,id);
                startActivity(i);
            }
        });

结果(根据单击项目时的其他活动(在本例中为第一个)):-

在此处输入图像描述


推荐阅读