Мы продолжаем собирать материалы о программировании в android. Все в одном месте. Лучшее и доступное. В наших планах составить мануал для программистов всех уровней, который будет собран из лучших и доступных, проверенных материалов. Сегодня мы предлагаем к рассмотрению статью о том, как работать с стандартной встроенной базой данных. В данной статье приведен пример реализации классов для работы с базой данных в Android.
У нас будет 3 активности которые будут содержать три разных типа контента. Первая будет у нас главной в ней мы будем вводить данные, во второй мы будем смотреть в списке что мы вводили и третья активность эта та в которой мы будем смотреть более подробные данные о выбранном поле в списке.

База наша будет элементарной всего три поля имя, фамилия и возраст. Итак давайте начнем, создадим три класса активности, которые будет выполнять наш функционал, и создадим три xml файла для разметки наших активностей.

Начнем мы с того что создадим три файла для создания базы данных:

Класс создания базы данных.

DatabaseOpenHelper.java
import database.DatabaseContract.Names;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.util.Log;

/** Класс создающий, удаляющий и редактирующий базу */
publicclassDatabaseOpenHelperextendsSQLiteOpenHelper{

       
privatestaticfinalString DATABASE_NAME ="db.db";
       
privatestaticfinalint DATABASE_VERSION =1;
       
privatestaticfinalString DEBUG_TAG =DatabaseOpenHelper.class.getSimpleName();
       
privatestaticfinalboolean LOGV =false;

       
publicDatabaseOpenHelper(Context context){

               
super(context, DATABASE_NAME,null, DATABASE_VERSION);
       
}

       
/** Удаление всех таблиц из базы
         *
         * @param db
         *            - object of SQLiteDatabase */

       
publicvoid dropTables(SQLiteDatabase db){

               
if(LOGV){
                       
Log.d(DEBUG_TAG,"onDropTables called");
               
}
                db
.execSQL("DROP TABLE IF EXISTS "+Names.TABLE_NAME);
       
}

       
@Override
       
publicvoid onCreate(SQLiteDatabase db){

               
if(LOGV){
                       
Log.v(DEBUG_TAG,"onCreate()");
               
}
                db
.execSQL("CREATE TABLE "+Names.TABLE_NAME +" ("+BaseColumns._ID
                               
+" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "+Names.NamesColumns.NAME
                               
+" TEXT NOT NULL, "+Names.NamesColumns.AGE +" INTEGER NOT NULL, "
                               
+Names.NamesColumns.FNAME +" TEXT NOT NULL );");
       
}

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

               
Log.d(DEBUG_TAG,"onUpgrade called");
       
}
}

В этом классе мы создаем базу которую дальше мы будем использовать. Собственно, больше нечего сказать.

DatabaseContract.java
import android.provider.BaseColumns;

publicclassDatabaseContract{

       
/** Describes History Table and model. */
       
publicstaticclassNames{

               
/** Default "ORDER BY" clause. */
               
//сортируем по фамилии в убывающем порядке
               
publicstaticfinalString DEFAULT_SORT =NamesColumns.FNAME +" DESC";
               
//имя таблицы
               
publicstaticfinalString TABLE_NAME ="People";
               
//поле имя
               
privateString name;
               
//наш айдишник
               
privatelong id;
               
//фамилия
               
privateString fname;
               
//и сколько лет
               
privateint age;
               
               
//
               
// Ниже идут сетеры и гетеры для захвата данных из базы
               
//
               
publicString getName(){

                       
return name;
               
}

               
publiclong getId(){

                       
return id;
               
}

               
publicString getFname(){

                       
return fname;
               
}

               
publicdouble getAge(){

                       
return age;
               
}

               
publicvoid setName(String name){

                       
this.name = name;
               
}

               
publicvoid setId(long id){

                       
this.id = id;
               
}

               
publicvoid setFname(String fname){

                       
this.fname = fname;
               
}

               
publicvoid setAge(int age){

                       
this.age = age;
               
}

               
/*
                 * (non-Javadoc)
                 *
                 * @see java.lang.Object#toString()
                 */

               
@Override
               
publicStringtoString(){

                       
StringBuilder builder =newStringBuilder();
                        builder
.append(fname);
                       
return builder.toString();
               
}

               
//Класс с именами наших полей в базе
               
publicclassNamesColumnsimplementsBaseColumns{

                       
/** Strings */
                       
publicstaticfinalString NAME ="name";
                       
/** String */
                       
publicstaticfinalString FNAME ="fname";
                       
/** String */
                       
publicstaticfinalString AGE ="age";
               
}
       
}
}

Дальше идет класс который обеспечивает запись, удаление и изменение данных.

ManController.java
package database;


import database.DatabaseContract.Names;
import database.DatabaseContract.Names.NamesColumns;

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.provider.BaseColumns;
import android.util.Log;

import java.util.ArrayList;

publicclassManController{

       
privatestaticfinalboolean LOGV =false;
       
privatestaticint maxRowsInNames =-1;
       
privatestaticfinalString TAG =ManController.class.getSimpleName();

       
privateManController(){

       
}

       
publicstaticint getMaxRowsInNames(){

               
return maxRowsInNames;
       
}

       
/**  Функция возвращает все данные из базы при запросе к ней
         *
         * @param context
         * @return */

       
publicstaticArrayList<Names> readNames(Context context){

               
ArrayList<Names> list =null;
               
try{
                       
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(context);
                       
SQLiteDatabase sqliteDB = dbhelper.getReadableDatabase();
                       
String[] columnsToTake ={BaseColumns._ID,NamesColumns.FNAME };
                       
Cursor cursor = sqliteDB.query(Names.TABLE_NAME, columnsToTake,null,null,null,null,
                                       
Names.DEFAULT_SORT);
                       
if(cursor.moveToFirst()){
                                list
=newArrayList<Names>();
                       
}
                       
while(cursor.moveToNext()){
                               
Names oneRow =newNames();
                                oneRow
.setId(cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID)));
                                oneRow
.setFname(cursor.getString(cursor.getColumnIndexOrThrow(NamesColumns.FNAME)));
                                list
.add(oneRow);
                       
}
                        cursor
.close();
                        dbhelper
.close();
               
}catch(Exception e){
                       
Log.e(TAG,"Failed to select Names.", e);
               
}
               
return list;
       
}

       
publicstaticvoid setMaxRowsInNames(int maxRowsInNames){

               
ManController.maxRowsInNames = maxRowsInNames;
       
}

       
/**Изменение строки в списке*/
       
publicstaticvoid update(Context context,String comment,long l){

               
try{
                       
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(context);
                       
SQLiteDatabase sqliteDB = dbhelper.getWritableDatabase();
                       
String quer =null;
                       
int countRows =-1;
                       
Cursor cursor = sqliteDB.query(Names.TABLE_NAME,newString[]{"count(*)"},null,null,null,
                                       
null,Names.DEFAULT_SORT);
                       
if(cursor.moveToFirst()){
                                countRows
= cursor.getInt(0);
                               
if(LOGV){
                                       
Log.v(TAG,"Count in Names table"+String.valueOf(countRows));
                               
}
                       
}
                        cursor
.close();
                        quer
=String.format("UPDATE "+Names.TABLE_NAME +" SET "+Names.NamesColumns.FNAME
                                       
+" = '"+ comment +"' WHERE "+BaseColumns._ID +" = "+ l);
                       
Log.d("",""+ quer);
                        sqliteDB
.execSQL(quer);
                        sqliteDB
.close();
                        dbhelper
.close();
               
}catch(SQLiteException e){
                       
Log.e(TAG,"Failed open database. ", e);
               
}catch(SQLException e){
                       
Log.e(TAG,"Failed to update Names. ", e);
               
}
       
}
       
       
/**Удаление строки из списка*/
       
publicstaticvoiddelete(Context context,long l){

                       
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(context);
                       
SQLiteDatabase sqliteDB = dbhelper.getWritableDatabase();
                        sqliteDB
.delete(Names.TABLE_NAME,BaseColumns._ID  +" = "+ l,null);
                        sqliteDB
.close();
                        dbhelper
.close();
       
}

       
/** Эта функция создает запрос которые дальше записывает данные в нашу базу данных
         *
         * @param context
         * @param latitude
         * @param longitude */

       
publicstaticvoid write(Context context,String name,String fname,int age){

               
try{
                       
//создали нашу базу и открыли для записи
                       
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(context);
                       
SQLiteDatabase sqliteDB = dbhelper.getWritableDatabase();
                       
String quer =null;
                       
int countRows =-1;
                       
//Открыли курсор для записи
                       
Cursor cursor = sqliteDB.query(Names.TABLE_NAME,newString[]{"count(*)"},null,null,null,
                                       
null,Names.DEFAULT_SORT);
                       
if(cursor.moveToFirst()){
                                countRows
= cursor.getInt(0);
                               
if(LOGV){
                                       
Log.v(TAG,"Count in Names table"+String.valueOf(countRows));
                               
}
                       
}
                        cursor
.close();
                       
if((maxRowsInNames ==-1)||(maxRowsInNames >= countRows)){
                               
//дальще наш запрос в базу для записи полученны х дынных из функции
                                quer
=String.format("INSERT INTO %s (%s, %s, %s) VALUES (%s, %s, %s);",
                                               
// таблица
                                               
Names.TABLE_NAME,
                                               
// колонки
                                               
Names.NamesColumns.NAME,Names.NamesColumns.AGE,
                                               
Names.NamesColumns.FNAME,
                                               
// поля
                                                name
, age, fname);
                       
}
                       
//закрыли всю базу
                        sqliteDB
.execSQL(quer);
                        sqliteDB
.close();
                        dbhelper
.close();
               
}catch(SQLiteException e){
                       
Log.e(TAG,"Failed open rimes database. ", e);
               
}catch(SQLException e){
                       
Log.e(TAG,"Failed to insert Names. ", e);
               
}
       
}
}


Теперь нам осталось создать три активности о которых я говорил в самом начале. Создаем первую и самую главную активность, которая будет осуществлять запись в базу:

MainActivity.java

import database.ManController;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;


publicclassMainActivity  extendsActivity{

   
@Override
   
publicvoid onCreate(Bundle savedInstanceState){

       
super.onCreate(savedInstanceState);
        setContentView
(R.layout.write_to_db);
       
       
finalEditText name =(EditText) findViewById(R.id.name);
       
finalEditText fname =(EditText) findViewById(R.id.fname);
       
finalEditText age =(EditText) findViewById(R.id.age);
       
Button btn =(Button) findViewById(R.id.button1);
        btn
.setOnClickListener(newOnClickListener(){
                       
                       
@Override
                       
publicvoid onClick(View arg0){
                               
ManController.write(getBaseContext(),'"'+name.getText().toString()+'"','"'+fname.getText().toString()+'"',Integer.parseInt(age.getText().toString()));
                       
}
               
});
   
}
   
   
@Override
       
publicboolean onCreateOptionsMenu(Menu menu){

                menu
.add(Menu.NONE,1,0,"Список записей");
               
returnsuper.onCreateOptionsMenu(menu);
       
}

       
@Override
       
publicboolean onOptionsItemSelected(MenuItem item){

               
switch(item.getItemId()){
                       
case1:{
                               
Intent intent =newIntent(this,ListActivity.class);
                                startActivity
(intent);
                       
}
                               
break;
               
}
               
returntrue;
       
}
}

Обратите внимание на кавычки
'"'+fname.getText().toString()+'"'
, которые необходимы для записи текстовых данных.  Числовые данные не нужно так выделять, так как они и так записываются.

Код разметки для MainActivity:

write_to_db.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"
   
android:orientation="vertical">

   
<EditText
       
android:id="@+id/name"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:ems="10">

       
<requestFocus/>
   
</EditText>
   
<EditText
       
android:id="@+id/fname"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:ems="10">

       
<requestFocus/>
   
</EditText>
   
<EditText
       
android:id="@+id/age"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:numeric="integer"
       
android:ems="10">

       
<requestFocus/>
   
</EditText>

   
<Button
       
android:id="@+id/button1"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:text="Button"/>

</LinearLayout>




Дальше мы создадим нашу активность со списком. Её код ниже:

ListActivity.java
package com.example.database;

import database.ManController;
import database.DatabaseContract.Names;
import database.DatabaseContract.Names.NamesColumns;
import database.DatabaseOpenHelper;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

publicclassListActivityextendsActivity{
       
       
finalContext context =this;
       
int rowId =0;
       
@Override
       
publicvoid onCreate(Bundle savedInstanceState){

               
super.onCreate(savedInstanceState);
                setContentView
(R.layout.listview);
               
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(getBaseContext());
               
SQLiteDatabase sqliteDB = dbhelper.getReadableDatabase();
               
finalString[]from={NamesColumns.FNAME,BaseColumns._ID };
               
finalCursor c = sqliteDB.query(Names.TABLE_NAME,null,null,null,null,null,
                               
Names.DEFAULT_SORT);
               
finalint i = c.getCount();
               
finalint[] to =newint[]{ R.id.text1 };
               
finalSimpleCursorAdapter adapter =newSimpleCursorAdapter(getApplicationContext(), R.layout.list,
                                c
,from, to);
               
finalListView lv =(ListView) findViewById(R.id.listView1);            
                lv
.setAdapter(adapter);
                lv
.setOnItemClickListener(newOnItemClickListener(){

                       
@Override
                       
publicvoid onItemClick(AdapterView<?> a,View v,int position,long id){

                               
Intent intent =newIntent(ListActivity.this,DataActivity.class);                              
                                intent
.putExtra("_id", id);
                                startActivity
(intent);
                                finish
();
                       
}
               
});
                lv
.setOnItemLongClickListener(newOnItemLongClickListener(){

                       
@Override
                       
publicboolean onItemLongClick(AdapterView<?> arg0,View arg1,finalint pos,long id){

                               
finalCharSequence[] items ={"Удалить","Переименовать"};
                               
AlertDialog.Builder builder3 =newAlertDialog.Builder(ListActivity.this);
                                builder3
.setTitle("Введите новое имя").setItems(items,
                                               
newDialogInterface.OnClickListener(){

                                                       
@Override
                                                       
publicvoid onClick(DialogInterface dialog,int item){

                                                               
switch(item){
                                                                       
case0:{
                                                                               
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(getBaseContext());
                                                                               
SQLiteDatabase sqliteDB = dbhelper.getReadableDatabase();
                                                                               
ManController.delete(getBaseContext(), adapter.getItemId(pos));        
                                                                               
finalCursor c = sqliteDB.query(Names.TABLE_NAME,null,null,null,null,null,
                                                                                               
Names.DEFAULT_SORT);
                                                                                adapter
.changeCursor©;
                                                                                dbhelper
.close();
                                                                                sqliteDB
.close();
                                                                       
}
                                                                               
break;
                                                                       
case1:{
                                                                               
// подключаем наш кастомный диалог лайаут
                                                                               
LayoutInflater li =LayoutInflater.from(context);
                                                                               
View promptsView = li.inflate(R.layout.promt,null);
                                                                               
AlertDialog.Builder alertDialogBuilder =newAlertDialog.Builder(
                                                                                                context
);
                                                                               
// делаем его диалогом
                                                                                alertDialogBuilder
.setView(promptsView);
                                                                               
finalEditText userInput =(EditText) promptsView
                                                                                               
.findViewById(R.id.editTextDialogUserInput);
                                                                               
// вешаем на него событие
                                                                                alertDialogBuilder
.setCancelable(false).setPositiveButton("OK",
                                                                                               
newDialogInterface.OnClickListener(){

                                                                                                       
@Override
                                                                                                       
publicvoid onClick(DialogInterface dialog,int id){

                                                                                                               
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(getBaseContext());
                                                                                                               
SQLiteDatabase sqliteDB = dbhelper.getReadableDatabase();
                                                                                                               
ManController.update(getBaseContext(), userInput
                                                                                                                               
.getText().toString(), adapter.getItemId(pos));        
                                                                                                               
finalCursor c = sqliteDB.query(Names.TABLE_NAME,null,null,null,null,null,
                                                                                                                               
Names.DEFAULT_SORT);
                                                                                                                adapter
.changeCursor©;
                                                                                                                dbhelper
.close();
                                                                                                                sqliteDB
.close();
                                                                                                       
}
                                                                                               
}).setNegativeButton("Cancel",
                                                                                               
newDialogInterface.OnClickListener(){

                                                                                                       
@Override
                                                                                                       
publicvoid onClick(DialogInterface dialog,int id){

                                                                                                                dialog
.cancel();
                                                                                                       
}
                                                                                               
});
                                                                               
// создаем диалог
                                                                               
AlertDialog alertDialog = alertDialogBuilder.create();
                                                                               
// показываем его
                                                                                alertDialog
.show();
                                                                       
}
                                                                               
break;
                                                               
}
                                                       
}
                                               
});
                                builder3
.show();
                               
returntrue;
                       
}
               
});
                dbhelper
.close();
                sqliteDB
.close();
       
}
}


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



Ниже я выложу три вьюшки, они нам понадобятся сохраните их у себя в res/layout по ходу дела разберетесь зачем они.

Эта разметка для нашего ListActivity.java.

listview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="fill_parent"
   
android:layout_height="fill_parent"
   
android:orientation="vertical">

   
<ListView
       
android:id="@+id/listView1"
       
android:layout_width="fill_parent"
       
android:layout_height="wrap_content">
   
</ListView>

</LinearLayout>

Эта вьюшка нам понадобится для вывода нашего списка в LisActivity.

list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 
xmlns:android="http://schemas.android.com/apk/res/android"
 
android:layout_width="fill_parent"
 
android:orientation="horizontal"
 
android:layout_height="wrap_content">

 
<TextView
     
android:id="@+id/text1"
     
android:layout_width="fill_parent"
     
android:layout_height="46dp"
     
android:textSize="25dip"
     
android:textColor="#000"/>

</LinearLayout>

Вьюшка нужна для редактирования полей в базе, она используется когда мы нажимаем после долгого нажатия на пункт меню «Переименовать».

promt.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:id="@+id/layout_root"
   
android:layout_width="fill_parent"
   
android:layout_height="fill_parent"
   
android:orientation="vertical"
   
android:padding="10dp">
 
   
<TextView
       
android:id="@+id/textView1"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="Введите новое имя"
       
android:textAppearance="?android:attr/textAppearanceLarge"/>
 
   
<EditText
       
android:id="@+id/editTextDialogUserInput"
       
android:layout_width="fill_parent"
       
android:layout_height="wrap_content">
 
       
<requestFocus/>
 
   
</EditText>
 
</LinearLayout>

Осталось разработать активность, которая показывается после короткого нажатия на выбраное поле в списке с фамилиями.

DataActivity.java
import database.DatabaseContract.Names;
import database.DatabaseContract.Names.NamesColumns;
import database.DatabaseOpenHelper;

import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;


publicclassDataActivityextendsActivity{

   
staticfinalString TAG =DataActivity.class.getSimpleName();
   
privateLong mRowId;

   
@Override
   
publicvoid onCreate(Bundle savedInstanceState){

       
super.onCreate(savedInstanceState);
        setContentView
(R.layout.test);
       
//получаем из инта нужный нам айдишник и открываем нужное поле
       
long id = getIntent().getLongExtra("_id",-6);
       
DatabaseOpenHelper dbhelper =newDatabaseOpenHelper(getBaseContext());
       
SQLiteDatabase sqliteDB = dbhelper.getReadableDatabase();
       
Cursor c = sqliteDB.query(Names.TABLE_NAME,null,BaseColumns._ID +"="+ id,null,null,null,
               
null);
       
TextView lv =(TextView) findViewById(R.id.response);
       
TextView tw =(TextView) findViewById(R.id.request);
       
//выводим все в текствьюхи
       
if(c.moveToFirst()){
            tw
.setText(c.getString(c.getColumnIndex(NamesColumns.NAME)));
            lv
.setText(c.getString(c.getColumnIndex(NamesColumns.AGE)));
       
}
        dbhelper
.close();
        sqliteDB
.close();
       
Log.v(TAG,"ID="+ id);
   
}
}

Код нашей разметки в активности:

test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="fill_parent"
   
android:layout_height="fill_parent"
   
android:orientation="vertical">

   
<TextView
       
android:id="@+id/request"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="TextView"
       
android:textSize="20sp"/>

   
<TextView
       
android:id="@+id/response"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="TextView"
       
android:textSize="20sp"/>

</LinearLayout>


Два текстовых поля

Вот и все, база готова, осталось только прописать активности в манифесте.

Скачать с GitHub & Скачать исходники

Вверх