求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
在Android中创建和使用数据库
 

作者:butter,发布于 2011-11-15

 

每个应用程序都要使用数据,Android应用程序也不例外,Android使用开源的、与操作系统无关的SQL数据库--SQLite,本文介绍的就是如何为你的Android应用程序创建和操作SQLite数据库。

数据库支持每个应用程序无论大小的生命线,除非你的应用程序只处理简单的数据,那么就需要一个数据库系统存储你的结构化数据,Android使用SQLite数据库,它是一个开源的、支持多操作系统的SQL数据库,在许多领域广泛使用,如Mozilla FireFox就是使用SQLite来存储配置数据的,iPhone也是使用SQLite来存储数据的。

在Android中,你为某个应用程序创建的数据库,只有它可以访问,其它应用程序是不能访问的,数据库位于Android设备/data/data/ databases文件夹中,在这篇文章中,你将会学习到如何在Android中创建和使用数据库。

SQLite数据库

使用Eclipse创建一个Android项目,取名为Database。

创建DBAdapter辅助类

操作数据库的最佳实践是创建一个辅助类,由它封装所有对数据库的复杂访问,对于调用代码而言它是透明的,因此我创建了一个DBAdapter的辅助类,由它创建、打开、关闭和使用SQLite数据库。

首先,在src/ 文件夹(在这个例子中是src/net.learn2develop.Database)下添加一个DBAdapter.java文件。

在DBAdapter.java文件中,导入所有你要使用到的命名空间:

package net.learn2develop.Databases;

  import android.content.ContentValues;

  import android.content.Context;

  import android.database.Cursor;

  import android.database.SQLException;

  import android.database.sqlite.SQLiteDatabase;

  import android.database.sqlite.SQLiteOpenHelper;

  import android.util.Log;

  public class DBAdapter

  {

  }

接下来创建一个数据库,取名为bookstitles,字段包括id,isbn,title,publisher

在DBAdapter.java文件中,定义清单1中常量。

清单1中定义DBAdapter.java文件中的常量

package net.learn2develop.Database;

  import android.content.ContentValues;

  import android.content.Context;

  import android.database.Cursor;

  import android.database.SQLException;

  import android.database.sqlite.SQLiteDatabase;

  import android.database.sqlite.SQLiteOpenHelper;

  import android.util.Log;

  public class DBAdapter

  {

      public static final String KEY_ROWID = "_id";

      public static final String KEY_ISBN = "isbn";

      public static final String KEY_TITLE = "title";

      public static final String KEY_PUBLISHER = "publisher";

      private static final String TAG = "DBAdapter";

      private static final String DATABASE_NAME = "books";

      private static final String DATABASE_TABLE = "titles";

      private static final int DATABASE_VERSION = 1;

      private static final String DATABASE_CREATE =

      "create table titles (_id integer primary key autoincrement, "

      + "isbn text not null, title text not null, "

      + "publisher text not null);";

      private final Context context;

  }

DATABASE_CREATE常量包括创建titles表的SQL语句。

在DBAdapter类中,你可以扩展SQLiteOpenHelper类,它是一个Android辅助类,主要用于数据库创建和版本管理。实际上,你可以覆盖onCreate()和onUpgrade()方法,如清单2所示。

清单2 在DBAdapter类中,扩展SQLiteOpenHelper类覆盖onCreate() 和 onUpgrade()方法

package net.learn2develop.Database;

  import android.content.ContentValues;

  import android.content.Context;

  import android.database.Cursor;

  import android.database.SQLException;

  import android.database.sqlite.SQLiteDatabase;

  import android.database.sqlite.SQLiteOpenHelper;

  import android.util.Log;

  public class DBAdapter

  {

      public static final String KEY_ROWID = "_id";

      public static final String KEY_ISBN = "isbn";

      public static final String KEY_TITLE = "title";

      public static final String KEY_PUBLISHER = "publisher";

      private static final String TAG = "DBAdapter";

      private static final String DATABASE_NAME = "books";

      private static final String DATABASE_TABLE = "titles";

      private static final int DATABASE_VERSION = 1;

      private static final String DATABASE_CREATE =

      "create table titles (_id integer primary key autoincrement, "

      + "isbn text not null, title text not null, "

      + "publisher text not null);";

      private final Context context;

      private DatabaseHelper DBHelper;

      private SQLiteDatabase db;

      public DBAdapter(Context ctx)

      {

          this.context = ctx;

          DBHelper = new DatabaseHelper(context);

      }

      private static class DatabaseHelper extends SQLiteOpenHelper

      {

          DatabaseHelper(Context context)

          {

              super(context, DATABASE_NAME, null, DATABASE_VERSION);

          }

          @Override

          public void onCreate(SQLiteDatabase db)

          {

              db.execSQL(DATABASE_CREATE);

          }

          @Override

          public void onUpgrade(SQLiteDatabase db, int oldVersion,

          int newVersion)

      {

          Log.w(TAG, "Upgrading database from version " + oldVersion

          + " to "

          + newVersion + ", which will destroy all old data");

          db.execSQL("DROP TABLE IF EXISTS titles");

          onCreate(db);

      }

     }

  }

onCreate()方法创建一个新的数据库,onUpgrade()方法用于升级数据库,这可以通过检查DATABASE_VERSION常量定义的值来实现,对于onUpgrade()方法而言,只不过是简单地删除表,然后在创建表而已。

现在你可以定义不同的方法来打开和关闭数据库,如清单3中的添加/编辑/删除/行的函数。

清单3 定义打开和关闭数据库以及增加/编辑/删除表中行的方法

public class DBAdapter

  {

      //...

      //...

      //---打开数据库---

      public DBAdapter open() throws SQLException

      {

          db = DBHelper.getWritableDatabase();

          return this;

      }

      //---关闭数据库---

      public void close()

      {

          DBHelper.close();

      }

      //---向数据库插入一个标题---

      public long insertTitle(String isbn, String title, String publisher)

      {

          ContentValues initialValues = new ContentValues();

          initialValues.put(KEY_ISBN, isbn);

          initialValues.put(KEY_TITLE, title);

          initialValues.put(KEY_PUBLISHER, publisher);

          return db.insert(DATABASE_TABLE, null, initialValues);

      }

      //---删除一个指定的标题---

      public boolean deleteTitle(long rowId)

      {

          return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;

      }

      //---检索所有标题---

      public Cursor getAllTitles()

      {

          return db.query(DATABASE_TABLE, new String[] {

          KEY_ROWID,

          KEY_ISBN,

          KEY_TITLE,

          KEY_PUBLISHER},

          null,

          null,

          null,

          null,

          null);

      }

      //---检索一个指定的标题---

      public Cursor getTitle(long rowId) throws SQLException

      {

          Cursor mCursor =

          db.query(true, DATABASE_TABLE, new String[] {

          KEY_ROWID,

          KEY_ISBN,

          KEY_TITLE,

          KEY_PUBLISHER

      },

      KEY_ROWID + "=" + rowId,

      null,

      null,

      null,

      null,

      null);

      if (mCursor != null) {

          mCursor.moveToFirst();

      }

  return mCursor;

  }

  //---更新一个标题---

  public boolean updateTitle(long rowId, String isbn,

  String title, String publisher)

  {

      ContentValues args = new ContentValues();

      args.put(KEY_ISBN, isbn);

      args.put(KEY_TITLE, title);

      args.put(KEY_PUBLISHER, publisher);

      return db.update(DATABASE_TABLE, args,

      KEY_ROWID + "=" + rowId, null) > 0;

    }

  }

    <!--EndFragment-->

注意Android使用Cursor类返回一个需要的值,Cursor作为一个指针从数据库查询返回结果集,使用Cursor允许Android更有效地管理它们需要的行和列,你使用ContentValues对象存储键/值对,它的put()方法允许你插入不同数据类型的键值。

清单4显示了完整的DBAdapter.java源代码。

清单4 DBAdapter.java完整源代码

package net.learn2develop.Database;

  import android.content.ContentValues;

  import android.content.Context;

  import android.database.Cursor;

  import android.database.SQLException;

  import android.database.sqlite.SQLiteDatabase;

  import android.database.sqlite.SQLiteOpenHelper;

  import android.util.Log;

  public class DBAdapter

  {

      public static final String KEY_ROWID = "_id";

      public static final String KEY_ISBN = "isbn";

      public static final String KEY_TITLE = "title";

      public static final String KEY_PUBLISHER = "publisher";

      private static final String TAG = "DBAdapter";

      private static final String DATABASE_NAME = "books";

      private static final String DATABASE_TABLE = "titles";

      private static final int DATABASE_VERSION = 1;

      private static final String DATABASE_CREATE =

      "create table titles (_id integer primary key autoincrement, "

      + "isbn text not null, title text not null, "

      + "publisher text not null);";

      private final Context context;

      private DatabaseHelper DBHelper;

      private SQLiteDatabase db;

      public DBAdapter(Context ctx)

      {

          this.context = ctx;

          DBHelper = new DatabaseHelper(context);

      }

      private static class DatabaseHelper extends SQLiteOpenHelper

      {

          DatabaseHelper(Context context)

          {

              super(context, DATABASE_NAME, null, DATABASE_VERSION);

          }

          @Override

          public void onCreate(SQLiteDatabase db)

          {

              db.execSQL(DATABASE_CREATE);

          }

          @Override

          public void onUpgrade(SQLiteDatabase db, int oldVersion,

          int newVersion)

          {

              Log.w(TAG, "Upgrading database from version " + oldVersion

              + " to "

              + newVersion + ", which will destroy all old data");

              db.execSQL("DROP TABLE IF EXISTS titles");

              onCreate(db);

          }

      }

      //---打开数据库---

      public DBAdapter open() throws SQLException

      {

          db = DBHelper.getWritableDatabase();

          return this;

      }

      //---关闭数据库---

      public void close()

      {

          DBHelper.close();

      }

      //---向数据库中插入一个标题---

      public long insertTitle(String isbn, String title, String publisher)

      {

          ContentValues initialValues = new ContentValues();

          initialValues.put(KEY_ISBN, isbn);

          initialValues.put(KEY_TITLE, title);

          initialValues.put(KEY_PUBLISHER, publisher);

          return db.insert(DATABASE_TABLE, null, initialValues);

      }

      //---删除一个指定标题---

      public boolean deleteTitle(long rowId)

      {

          return db.delete(DATABASE_TABLE, KEY_ROWID +

  "=" + rowId, null) > 0;

      }

      //---检索所有标题---

      public Cursor getAllTitles()

      {

          return db.query(DATABASE_TABLE, new String[] {

          KEY_ROWID,

          KEY_ISBN,

          KEY_TITLE,

          KEY_PUBLISHER},

          null,

          null,

          null,

          null,

          null);

      }

      //---检索一个指定标题---

      public Cursor getTitle(long rowId) throws SQLException

      {

          Cursor mCursor =

          db.query(true, DATABASE_TABLE, new String[] {

          KEY_ROWID,

          KEY_ISBN,

          KEY_TITLE,

          KEY_PUBLISHER

      },

      KEY_ROWID + "=" + rowId,

      null,

      null,

      null,

      null,

      null);

      if (mCursor != null) {

          mCursor.moveToFirst();

      }

      return mCursor;

  }

  //---更新一个标题---

  public boolean updateTitle(long rowId, String isbn,

  String title, String publisher)

  {

      ContentValues args = new ContentValues();

      args.put(KEY_ISBN, isbn);

      args.put(KEY_TITLE, title);

      args.put(KEY_PUBLISHER, publisher);

      return db.update(DATABASE_TABLE, args,

      KEY_ROWID + "=" + rowId, null) > 0;

     }

  }

使用数据库

现在你已经可以利用创建的辅助类来使用数据库了,在DatabaseActivity.java文件中,创建一个DBAdapter类的实例:

package net.learn2develop.Database;

  import android.app.Activity;

  import android.os.Bundle;

  public class DatabaseActivity extends Activity {

      /** Called when the activity is first created. */

      @Override

      public void onCreate(Bundle savedInstanceState) {

          super.onCreate(savedInstanceState);

          setContentView(R.layout.main);

          DBAdapter db = new DBAdapter(this);

      }

  }

增加一个标题

如果想在titles表中增加一个标题,可以使用DBAdapter类的insertTitle()方法:

public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  DBAdapter db = new DBAdapter(this);

  //---add 2 titles---

  db.open();

  long id;

  id = db.insertTitle(

  "0470285818",

  "C# 2008 Programmer's Reference",

  "Wrox");

  id = db.insertTitle(

  "047017661X",

  "Professional Windows Vista Gadgets Programming",

  "Wrox");

  db.close();

}

insertTitle()方法返回插入行的ID,如果在添加过程中遇到错误,它就返回-1。

如果你分析Android设备/模拟器的文件系统,你可以看到book数据库创建在database文件夹下,如图3所示。

图3 database文件夹

检索所有标题

想要检索titles表中的所有标题,可以使用DBAdapter类的getAllTitles()方法,如清单5所示。

清单5 使用DBAdapter类的getAllTitles()方法检索titles表中的所有标题

package net.learn2develop.Database;

  import android.app.Activity;

  import android.database.Cursor;

  import android.os.Bundle;

  import android.widget.Toast;

  public class DatabaseActivity extends Activity {

      /** Called when the activity is first created. */

      @Override

      public void onCreate(Bundle savedInstanceState)

      {

          super.onCreate(savedInstanceState);

          setContentView(R.layout.main);

          DBAdapter db = new DBAdapter(this);

          //---获取所有标题---

          db.open();

          Cursor c = db.getAllTitles();

          if (c.moveToFirst())

          {

              do {

               DisplayTitle(c);

              } while (c.moveToNext());

          }

          db.close();

      }

  }

返回的结果是一个Cursor对象,如果要显示所有标题,你首先应该调用Cursor对象的moveToFirst()方法,如果它成功(意味着至少有一行有效),使用DisplayTitle()方法显示详细的标题,要移动到下一个标题,可以调用Cursor对象的moveToNext()方法,下面是DisplayTitle()方法的定义:

public void DisplayTitle(Cursor c)

{

  Toast.makeText(this,

  "id: " + c.getString(0) + " " +

  "ISBN: " + c.getString(1) + " " +

  "TITLE: " + c.getString(2) + " " +

  "PUBLISHER: " + c.getString(3),

  Toast.LENGTH_LONG).show();

}

图4显示Toast类,它从数据库中检索并显示一个标题。

图4 Toast类

检索单个标题

想要通过ID检索单个标题,可以使用DBAdapter类的getTitle()方法:

public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  DBAdapter db = new DBAdapter(this);

  //---get a title---

  db.open();

  Cursor c = db.getTitle(2);

  if (c.moveToFirst())

  DisplayTitle(c);

  else

  Toast.makeText(this, "No title found",

  Toast.LENGTH_LONG).show();

  db.close();

}

返回的结果是一个Cursor对象,如果返回一行,可以使用DisplayTitle()方法显示标题的详细信息,否则就使用Toast类显示一个错误消息。

更新一个标题

要更新一个特定的标题,可以调用DBAdapter的updateTitle()方法,传递想要更新的标题的ID给它就可以了,如清单6所示。

清单6 调用DBAdapter类的updateTitle()方法更新标题

@Override

 public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  DBAdapter db = new DBAdapter(this);

  //---更新标题---

  db.open();

  if (db.updateTitle(1,

  "0470285818",

  "C# 2008 Programmer's Reference",

  "Wrox Press"))

  Toast.makeText(this, "Update successful.",

  Toast.LENGTH_LONG).show();

  else

  Toast.makeText(this, "Update failed.",

  Toast.LENGTH_LONG).show();

  //-------------------

  //---检索相同的标题---

  Cursor c = db.getTitle(1);

  if (c.moveToFirst())

  DisplayTitle(c);

  else

  Toast.makeText(this, "No title found",

  Toast.LENGTH_LONG).show();

  //-------------------

  db.close();

}

如果更新成功会显示一条表示成功的消息,同时,你可以检索刚刚更新的标题看更新结果是否正确。

删除一个标题

想要删除一个标题,可以调用DBAdapter类的deleteTitle()方法,传递你想要删除的标题的ID即可:

@Override

  public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  DBAdapter db = new DBAdapter(this);

  //---delete a title---

  db.open();

  if (db.deleteTitle(1))

  Toast.makeText(this, "Delete successful.",

  Toast.LENGTH_LONG).show();

  else

  Toast.makeText(this, "Delete failed.",

  Toast.LENGTH_LONG).show();

  db.close();

}

如果删除成功会显示一条表示成功的消息。

升级数据库

要升级数据库,修改DBAdapter类中DATABASE_VERSION常量的值比之前的值大,如之前的值是1,将其改为2:

public class DBAdapter

{

  public static final String KEY_ROWID = "_id";

  public static final String KEY_ISBN = "isbn";

  public static final String KEY_TITLE = "title";

  public static final String KEY_PUBLISHER = "publisher";

  private static final String TAG = "DBAdapter";

  private static final String DATABASE_NAME = "books";

  private static final String DATABASE_TABLE = "titles";

  //---change this to a higher value---

  private static final int DATABASE_VERSION = 2;

  private static final String DATABASE_CREATE =

  "create table titles (_id integer primary key autoincrement, "

  + "isbn text not null, title text not null, "

  + "publisher text not null);";

当你再次运行这个应用程序时,你会在Eclipse的LogCat窗口中看到数据库已经升级的消息,如图5所示。

图5 LogCat窗口-消息显示数据库升级成功

简化数据库访问

使用DBAdapter类,可以简化你的Android应用程序访问数据库记录的操作,一个重要的事情是在Android中创建的SQLite数据库只有创建它的应用程序可以访问它。如果你要共享数据,你需要使用一个内容提供器,这个将在以后的文章中再介绍了。

<!--EndFragment-->

<!--EndFragment-->

<!--EndFragment-->


相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

 
分享到
 
 
     


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...