使用ListView在下一个活动中显示数据库详细信息

时间:2019-02-26 18:26:42

标签: android database sqlite listview android-sqlite

我是Android Studio的新手,

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

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

数据库文件位于资产文件夹中。

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

这是我的代码,我只能成功在ListView中显示“ title”列,而其余部分我一无所知。

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>

1 个答案:

答案 0 :(得分:2)

您需要

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

示例

以下是基于您的问题的示例。

数据库

名为 mydb 的数据库,也就是资产文件夹中名为 mydb 的文件,其表 mytable 包含以下内容:-

enter image description here

布局

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

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

DatabaseHelper

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

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;
    }
}

MainActivity

这执行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的屏幕截图:-

enter image description here

其他

将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的详细信息,该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用作额外内容,最后启动其他活动,例如在上面的活动中,可以使用以下内容代替(以及(如果需要))Toast:-

        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);
            }
        });

结果(根据单击项目时的其他活动(在这种情况下为第一个)):-

enter image description here