Отображение сведений о базе данных в следующем упражнении с использованием ListView - PullRequest
0 голосов
/ 26 февраля 2019

Я новичок в Android Studio,

У меня уже есть файл базы данных с 3 столбцами (идентификатор, заголовок, подробности)

Я хочу создать ListView, содержащий «заголовок» из базы данныхи когда я щелкаю один из заголовков, он переходит к следующему действию и показывает «детали» из заголовка, который я щелкнул ранее.

Файл базы данных находится в папке ресурсов.

I'mиспользуя последнюю версию Android Studio, пожалуйста, помогите мне XML, Java и код манифеста.Спасибо.

вот мой код, я только успешно показываю столбец 'title' в 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>

1 Ответ

0 голосов
/ 26 февраля 2019

Вам необходимо

  1. добавить ListView к соответствующему макету начальной операции.
  2. создать вспомогательный класс базы данных, который будет:
    1. Проверьте, чтобы увидетьесли база данных уже существует
    2. Если база данных не существует, скопируйте базу данных из папки ресурсов.
    3. предоставьте методы для доступа к данным по мере необходимости (в случае заполнения Listview метод будетпотребуется для извлечения данных, которые должны быть перечислены)
  3. в начальном действии получить экземпляр класса помощника базы данных
  4. получить ListView через его идентификатор.
  5. создание подходящего адаптера для ListView.
  6. настройка ListView на использование адаптера
  7. Добавление прослушивателя onItemClick в ListView, который будет извлекать достаточные сведения (идентификатор) из выбранного элемента., установив Intent extra (s) с деталями, а затем запустите другое действие (которое затем может извлечь детали из Intent).

Пример

Ниже приведен пример, основанный на вашем вопросе.

База данных

База данных с именем mydb и, таким образом, это файл с именем mydb в папках ресурсов есть таблица mytable , которая содержит: -

enter image description here

Макет

Простой макет, включает Listview, которому был присвоен идентификатор, который использовался для действия с именем MainActivity , код для ListView: -

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

DatabaseHelper

Помощник по базе данных был создан как DBHelper.java .При создании экземпляра он проверяет, существует ли база данных в виде файла, а если нет, то пытается скопировать базу данных из папки ресурсов (возникает исключение времени выполнения, если происходит сбой, например, если актив не существует).База данных затем открывается.Существует один открытый метод getAllFromMytable , который возвращает курсор со всеми строками из таблицы 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;
    }
}

MainActivity

Это выполняет 4-7, за исключением того, что довольночем запуск другого действия, детали выбранного элемента в 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 запускается при запуске действия.

Результат

Снимок экрана с тостом: -

enter image description here

Дополнительно

Передача идентификатора другому действию, затемизвлечение столбца сведений в этом упражнении.

Сначала добавьте новый метод в класс помощника базы данных, чтобы столбец сведений можно было возвращать в виде строки и получать в соответствии с id * 1094.*

например, DBHelВ приведенном выше per.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, соответственно, изменяет манифест).

Это действие может быть чем-то вроде (это будет отображать детали в соответствии с идентификатором, переданным как long через дополнительное намерение, используемое для начала действия): -

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, которое можно использовать для запуска другого действия, затем добавьте идентификатор в качестве дополнительного и, наконец, запустите другое действие, например, в вышеупомянутом упражнении можно использовать следующее (а также, если вы хотите)Тост: -

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

Результат (в соответствии с другим действием при нажатии на элемент (в данном случае 1-й)): -

enter image description here

...