Android作为目前主流的移动操作系统,完全符合SQLite占用资源少的优势,故在Android平台上,集成了一个嵌入式关系型数据库—SQLite。如果想要开发 Android 应用程序,需要在 Android 上存储数据,使用SQLite 数据库是一种非常好的选择。在一般程序中使用数据库的过程都可以框架化,套路化,实例如下:
表说明:
1.班级 classes:
class_id 主键 class_name
2.学生 students:
student_id 主键 student_name score class_id 外键
创建表:
CREATE TABLE classes(class_id varchar(10) primary key , class_name varchar(20))
CREATE TABLE students(student_id varchar(10) primary key ,
student_name varchar(20) ,
score varchar(4) ,
class_id varchar(10),
foreign key (class_id) references classes(class_id) **on delete cascade on update cascade**)
**1. 继承扩展 SQLiteOpenHelper 创建数据库和对应表**
~~~
package com.tang.databasedemo;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DBHelper extends SQLiteOpenHelper
{
public DBHelper(Context context) {
super(context, "info.db", null, 1);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db)
{
// TODO Auto-generated method stub
String classesSQL = "CREATE TABLE classes(class_id varchar(10) primary key , " +
"class_name varchar(20))";
String studentsSQL = "CREATE TABLE students(student_id varchar(10) primary key , " +
"student_name varchar(20) ,score varchar(4) ,class_id varchar(10), " +
"foreign key (class_id) references classes(class_id) " +
"on delete cascade on update cascade )";
db.execSQL(classesSQL);
Log.d("my", "create table classes:"+classesSQL);
db.execSQL(studentsSQL);
Log.d("my", "create table students:"+studentsSQL);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
// TODO Auto-generated method stub
}
}
~~~
**2. 创建学生(Class)学生(Student)实体**
~~~
package com.tang.databasedemo;
import android.util.Log;
public class Class
{
private String classId;
private String className;
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String toString() {
return "Class--->"+"classId:"+classId+" className:"+className;
}
}
~~~
~~~
package com.tang.databasedemo;
public class Student
{
private String studentId;
private String studentName;
private String score;
private String classId;
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String toString()
{
return "Student--->"+"studentId:"+studentId+" studentName:"+studentName+" score:"+score+" classId:"+classId;
}
}
~~~
**3. 创建DBServer类,在该类中定义增删改查等方法来操作数据库**
~~~
package com.tang.databasedemo;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class DBServer
{
private DBHelper dbhelper;
public DBServer(Context context)
{
this.dbhelper = new DBHelper(context);
}
/**
* 添加班级
* @param entity
*/
public void addClass(Class entity)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Object[] arrayOfObject = new Object[2];
arrayOfObject[0] = entity.getClassId();
arrayOfObject[1] = entity.getClassName();
localSQLiteDatabase.execSQL("insert into classes(class_id,class_name) values(?,?)", arrayOfObject);
localSQLiteDatabase.close();
}
/**
* 添加学生
* @param entity
*/
public void addStudent(Student entity)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Object[] arrayOfObject = new Object[4];
arrayOfObject[0] = entity.getStudentId();
arrayOfObject[1] = entity.getStudentName();
arrayOfObject[2] = entity.getScore();
arrayOfObject[3] = entity.getClassId();
localSQLiteDatabase.execSQL("insert into students(student_id,student_name,score,class_id) values(?,?,?,?)", arrayOfObject);
localSQLiteDatabase.close();
}
/**
* 删除一个班级
* 同时会删除students中该班级的学生
* @param class_id
*/
public void deleteClass(String class_id)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
//设置了级联删除和级联更新
//在执行有级联关系的语句的时候必须先设置“PRAGMA foreign_keys=ON”
//否则级联关系默认失效
localSQLiteDatabase.execSQL("PRAGMA foreign_keys=ON");
Object[] arrayOfObject = new Object[1];
arrayOfObject[0] =class_id;
localSQLiteDatabase.execSQL("delete from classes where class_id=?", arrayOfObject);
localSQLiteDatabase.close();
}
/**
* 删除一个学生
* @param student_id
*/
public void deleteStudent(String student_id)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Object[] arrayOfObject = new Object[1];
arrayOfObject[0] =student_id;
localSQLiteDatabase.execSQL("delete from students where student_id=?", arrayOfObject);
localSQLiteDatabase.close();
}
/**
* 修改学生信息
* @param entity
*/
public void updateStudentInfo(Student entity)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Object[] arrayOfObject = new Object[4];
arrayOfObject[0] = entity.getStudentName();
arrayOfObject[1] = entity.getScore();
arrayOfObject[2] = entity.getClassId();
arrayOfObject[3] = entity.getStudentId();
localSQLiteDatabase.execSQL("update students set student_name=?,score=?,class_id=? where student_id=?", arrayOfObject);
localSQLiteDatabase.close();
}
/**
* 使用班级编号查找该班级所有学生
* @param classId
* @return
*/
public List<Student> findStudentsByClassId(String classId)
{
List<Student> localArrayList=new ArrayList<Student>();
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select student_id, student_name ,score from students " +
"where class_id=? order by score desc", new String[]{classId});
while (localCursor.moveToNext())
{
Student temp=new Student();
temp.setStudentId(localCursor.getString(localCursor.getColumnIndex("student_id")));
temp.setStudentName(localCursor.getString(localCursor.getColumnIndex("student_name")));
temp.setScore(localCursor.getString(localCursor.getColumnIndex("score")));
temp.setClassId(classId);
localArrayList.add(temp);
}
localSQLiteDatabase.close();
return localArrayList;
}
/**
* 使用班级名查找该班级所有学生
* @param className
* @return
*/
public List<Student> findStudentsByClassName(String className)
{
List<Student> localArrayList=new ArrayList<Student>();
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select student_id, student_name,score,classes.class_id from students,classes" +
" where students.class_id=classes.class_id and classes.class_name =? order by score asc" , new String[]{className});
while (localCursor.moveToNext())
{
Student temp=new Student();
temp.setStudentId(localCursor.getString(localCursor.getColumnIndex("student_id")));
temp.setStudentName(localCursor.getString(localCursor.getColumnIndex("student_name")));
temp.setScore(localCursor.getString(localCursor.getColumnIndex("score")));
temp.setClassId(localCursor.getString(3));
localArrayList.add(temp);
}
localSQLiteDatabase.close();
return localArrayList;
}
/**
* 查找所有学生
* @param className
* @return
*/
public List<Student> findAllStudents()
{
List<Student> localArrayList=new ArrayList<Student>();
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select * from students " +
"where 1=1 order by score desc ", null);
while (localCursor.moveToNext())
{
Student temp=new Student();
temp.setStudentId(localCursor.getString(localCursor.getColumnIndex("student_id")));
temp.setStudentName(localCursor.getString(localCursor.getColumnIndex("student_name")));
temp.setScore(localCursor.getString(localCursor.getColumnIndex("score")));
temp.setClassId(localCursor.getString(localCursor.getColumnIndex("class_id")));
localArrayList.add(temp);
}
localSQLiteDatabase.close();
return localArrayList;
}
/**
* 取得所有班级
* @return
*/
public List<Class> findAllClasses()
{
List<Class> localArrayList=new ArrayList<Class>();
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select * from classes " +
"where 1=1", null);
while (localCursor.moveToNext())
{
Class temp=new Class();
temp.setClassId(localCursor.getString(localCursor.getColumnIndex("class_id")));
temp.setClassName(localCursor.getString(localCursor.getColumnIndex("class_name")));
localArrayList.add(temp);
}
localSQLiteDatabase.close();
return localArrayList;
}
/**
* 成绩最好
* @return
*/
public Student findMaxScoreStudent()
{
Student temp =new Student();
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select student_id,student_name,class_id,max(score) from students " +
"where 1=1",null );
localCursor.moveToFirst();
temp.setStudentId(localCursor.getString(0));
temp.setStudentName(localCursor.getString(1));
temp.setClassId(localCursor.getString(2));
temp.setScore(localCursor.getString(3));
return temp;
}
/**
* 查找是否有该学生
* @param studentId
* @return
*/
public boolean isStudentsExists(String studentId)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select count(*) from students " +
"where student_id=?", new String[]{studentId});
localCursor.moveToFirst();
if(localCursor.getLong(0)>0)
return true;
else
return false;
}
/**
* 确认该班级是否存在
* @param classId
* @return
*/
public boolean isClassExists(String s)
{
SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
Cursor localCursor = localSQLiteDatabase.rawQuery("select count(*) from classes " +
"where class_id=? or class_name=?", new String[]{s,s});
localCursor.moveToFirst();
if(localCursor.getLong(0)>0)
return true;
else
return false;
}
}
~~~
**4.调用DBServer里的方法,操作数据**
~~~
package com.tang.databasedemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.text.AlteredCharSequence;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener {
private List<Class> classData =new ArrayList<Class>();
private List<Student> studentsData =new ArrayList<Student>();
private static final String className ="A/B/C/D/E";
private static final String studentName ="彭大/黄二/张三/李四/王五/郑六/田七/周八/叶九/孔十/萧十一";
private DBServer db;
private SharedPreferences share;
private SharedPreferences.Editor editor;
private String info ="";
private EditText editText;
private Button b,b1,b2,b3,b4,b5,b6;
private EditText sId,sName,score,cId,cName;
private Handler hander =new Handler()
{
@Override
public void handleMessage(Message msg)
{
// TODO Auto-generated method stub
if(msg.what==0)
{
sId.setText("");
sName.setText("");
score.setText("");
cName.setText("");
cId.setText("");
}
else if(msg.what==1)
{
db.deleteClass((String)msg.obj);
info += "删除一个班级及班级里面的学生:班级Id:"+(String)msg.obj;
editText.setText(info);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
share = getSharedPreferences("DatabaseDamo", 0);
editor =share.edit();
db=new DBServer(this);
if(share.getInt("times", 0)==0)
{
initDatabase();
editor.putInt("times", 1);
editor.commit();
}
}
private void initView()
{
editText = (EditText) findViewById(R.id.info);
sId = (EditText) findViewById(R.id.studentId);
sName = (EditText) findViewById(R.id.studentName);
score = (EditText) findViewById(R.id.score);
cId = (EditText) findViewById(R.id.classId);
cName = (EditText) findViewById(R.id.className);
b =(Button) findViewById(R.id.button);
b1 =(Button) findViewById(R.id.button1);
b2 =(Button) findViewById(R.id.button2);
b3 =(Button) findViewById(R.id.button3);
b4 =(Button) findViewById(R.id.button4);
b5 =(Button) findViewById(R.id.button5);
b6 =(Button) findViewById(R.id.button6);
b.setOnClickListener(this);
b1.setOnClickListener(this);
b2.setOnClickListener(this);
b3.setOnClickListener(this);
b4.setOnClickListener(this);
b5.setOnClickListener(this);
b6.setOnClickListener(this);
}
private void initDatabase()
{
info="";
editText.setText("");
String []classTemp = className.split("/");
Class c;
for(int i=0;i<classTemp.length;i++)
{
c=new Class();
c.setClassName(classTemp[i]);
c.setClassId("00"+i);
db.addClass(c);
info+= '\n'+"add to database classes:"+c.toString();
}
String []studentTemp = studentName.split("/");
Student s;
for(int j=0;j<studentTemp.length;j++)
{
s=new Student();
s.setStudentName(studentTemp[j]);
s.setStudentId("2014050"+j);
s.setClassId("00"+new Random().nextInt(classTemp.length));
s.setScore(String.valueOf(new Random().nextInt(100)+1));
db.addStudent(s);
info+= '\n'+ "add to database students:"+'\n'+s.toString();
}
editText.setText(info);
}
private void addAStudent()
{
info ="";
editText.setText("");
String tempSID = sId.getText().toString();
String tempSName = sName.getText().toString();
String tempScore = score.getText().toString();
String tempCID = cId.getText().toString();
if(checkInfo(tempSID)&&checkInfo(tempSName)&&checkInfo(tempScore)&&checkInfo(tempCID))
{
Student temp =new Student();
temp.setStudentId(tempSID);
temp.setStudentName(tempSName);
temp.setScore(tempScore);
temp.setClassId(tempCID);
db.addStudent(temp);
info+= "add to database students:"+'\n'+temp.toString();
}
else
{
info += "添加一个学生失败:缺少必要信息,请确认studentId,studentName,score,classId的信息是否完整!";
}
editText.setText(info);
}
private void deleteAClass()
{
info ="";
editText.setText("");
final String tempCID = cId.getText().toString();
if(checkInfo(tempCID))
{
if(db.isClassExists(tempCID))
{
new AlertDialog.Builder(this)
.setTitle("提示:")
.setMessage("删除一个班级将会删除该班的所有学生信息,确定?")
.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Message msg =new Message();
msg.what = 1;
msg.obj = tempCID;
hander.sendMessage(msg);
}
})
.setNegativeButton("取消", null)
.show();
}
else
info += "删除一个班级失败:查无此对应班级,请确认classId的信息是否正确!";
}
else
{
info += "删除一个班级失败:缺少必要信息,请确认classId的信息是否完整!";
}
editText.setText(info);
}
private void deleteAStudent()
{
info ="";
editText.setText("");
String tempSID = sId.getText().toString();
if(checkInfo(tempSID))
{
if(db.isStudentsExists(tempSID))
{
db.deleteStudent(tempSID);
info += "删除一个学生:学生Id:"+tempSID;
}
else
info += "删除一个学生失败:查无此对应学生,请确认studentId的信息是否正确!";
}
else
{
info += "删除一个学生失败:缺少必要信息,请确认studentId的信息是否完整!";
}
editText.setText(info);
}
private void updateStudent()
{
info ="";
editText.setText("");
String tempSID = sId.getText().toString();
String tempSName = sName.getText().toString();
String tempScore = score.getText().toString();
String tempCID = cId.getText().toString();
if(checkInfo(tempSID)&&checkInfo(tempSName)&&checkInfo(tempScore)&&checkInfo(tempCID))
{
if(db.isStudentsExists(tempSID))
{
Student temp =new Student();
temp.setStudentId(tempSID);
temp.setStudentName(tempSName);
temp.setScore(tempScore);
temp.setClassId(tempCID);
db.updateStudentInfo(temp);
info+= "update database students:"+'\n'+temp.toString();
}
else
{
Student temp =new Student();
temp.setStudentId(tempSID);
temp.setStudentName(tempSName);
temp.setScore(tempScore);
temp.setClassId(tempCID);
db.addStudent(temp);
info+= "没有找到对应ID的学生,将此学生添加到数据库!"+'\n'+
"add to database students:"+'\n'+temp.toString();
}
}
else
{
info += "更新学生失败:缺少必要信息,请确认studentId,studentName,score,classId的信息是否完整!";
}
editText.setText(info);
}
/**
* 打印某班的学生
*/
private void printStudentsOfClass()
{
info ="";
editText.setText("");
String tempCID = cId.getText().toString();
String tempCName = cName.getText().toString();
if(checkInfo(tempCID))
{
if(db.isClassExists(tempCID))
{
info += "使用ID查询";
studentsData.clear();
studentsData= db.findStudentsByClassId(tempCID);
}
else
{
info += "该ID对应的班级不存在";
}
}
else if(checkInfo(tempCName))
{
if(db.isClassExists(tempCName))
{
info += "使用Name查询";
studentsData.clear();
studentsData = db.findStudentsByClassName(tempCName);
}
else
{
info += "该Name对应的班级不存在";
}
}
else
{
studentsData.clear();
info += "查找学生失败:缺少必要信息,请确认classId或className的信息是否完整!";
}
for(int i=0;i<studentsData.size();i++)
{
info+= '\n'+studentsData.get(i).toString();
}
editText.setText(info);;
}
private void printMaxScoreStudent()
{
info ="";
editText.setText("");
Student temp =db.findMaxScoreStudent();
info+= '\n'+temp.toString();
editText.setText(info);;
}
private void getAllStudent()
{
studentsData.clear();
studentsData = db.findAllStudents();
for(int i=0;i<studentsData.size();i++)
{
info+= '\n'+studentsData.get(i).toString();
}
}
private void getAllClass()
{
classData.clear();
classData = db.findAllClasses();
for(int i=0;i<classData.size();i++)
{
info+= '\n'+classData.get(i).toString();
}
}
private void printAllInfo()
{
info ="";
editText.setText("");
getAllStudent();
getAllClass();
editText.setText(info);
}
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
int id = v.getId();
switch(id)
{
case R.id.button:
printAllInfo();
break;
case R.id.button1:
addAStudent();
break;
case R.id.button2:
deleteAStudent();
break;
case R.id.button3:
deleteAClass();
break;
case R.id.button4:
updateStudent();
break;
case R.id.button5:
printStudentsOfClass();
break;
case R.id.button6:
printMaxScoreStudent();
break;
}
hander.sendEmptyMessageDelayed(0, 5000);
}
private boolean checkInfo(String s)
{
if(s.equals("")||s==null)
return false;
else
return true;
}
}
~~~
附图一张:
![](https://box.kancloud.cn/2016-08-18_57b550bbb1280.jpg)
**注:**
1 . 关于游标(Cursor)
在查询返回的是一个Cursor类型的对象,它是一个指针,且永远都不会为空,所以,当查询某语句,并判断返回值是否为空时,切勿用cursor==null表示。而有个方法,cursor.getCount()==0就能判断其结果值是否为空了。
close()
关闭游标,释放资源
copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) yB
在缓冲区中检索请求的列的文本,将将其存储
getColumnCount()
返回所有列的总数
getColumnIndex(String columnName)
返回指定列的名称,如果不存在返回-1
getColumnIndexOrThrow(String columnName)
从零开始返回指定列名称,如果不存在将抛出IllegalArgumentException 异常。
getColumnName(int columnIndex)
从给定的索引返回列名
getColumnNames()
返回一个字符串数组的列名
getCount()
返回Cursor 中的行数
moveToFirst()
移动光标到第一行
moveToLast()
移动光标到最后一行
moveToNext()
移动光标到下一行
moveToPosition(int position)
移动光标到一个绝对的位置
moveToPrevious()
移动光标到上一行
2. 关于**on delete cascade on update cascade**级联更新和级联删除
SQLite在3.6.19版本中才开始支持外键约束,但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能每次都要需要使用如下语句:PRAGMA foreign_keys = ON来打开。也就是说,在执行删除一个班级的语句的时候需要执行db.execSQL("PRAGMA foreign_keys=ON")
可见:[http://blog.csdn.net/tangnengwu/article/details/25980263](http://blog.csdn.net/tangnengwu/article/details/25980263)
3.关于getWritableDatabase()和getReadableDatabase()
这2个方法都可以获取SQLiteDatabase的实例,当使用getWritableDatabase() 方法打开数据库时,一旦数据库的磁盘空间满了,数据库在执行写操作的时候就会出错,
而getReadableDatabase()方法则是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。如果该问题成功
解决,则只读数据库对象就会关闭,然后返回一个可读写的数据库对象。也就是说getReadableDatabase()将getWritableDatabase()在安全上进行了优化。
在4.4的源码中:/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java
~~~
/**
* Create and/or open a database that will be used for reading and writing.
* The first time this is called, the database will be opened and
* {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
* called.
*
* <p>Once opened successfully, the database is cached, so you can
* call this method every time you need to write to the database.
* (Make sure to call {@link #close} when you no longer need the database.)
* Errors such as bad permissions or a full disk may cause this method
* to fail, but future attempts may succeed if the problem is fixed.</p>
*
* <p class="caution">Database upgrade may take a long time, you
* should not call this method from the application main thread, including
* from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
*
* @throws SQLiteException if the database cannot be opened for writing
* @return a read/write database object valid until {@link #close} is called
*/
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
/**
* Create and/or open a database. This will be the same object returned by
* {@link #getWritableDatabase} unless some problem, such as a full disk,
* requires the database to be opened read-only. In that case, a read-only
* database object will be returned. If the problem is fixed, a future call
* to {@link #getWritableDatabase} may succeed, in which case the read-only
* database object will be closed and the read/write object will be returned
* in the future.
*
* <p class="caution">Like {@link #getWritableDatabase}, this method may
* take a long time to return, so you should not call it from the
* application main thread, including from
* {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
*
* @throws SQLiteException if the database cannot be opened
* @return a database object valid until {@link #getWritableDatabase}
* or {@link #close} is called.
*/
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
private SQLiteDatabase getDatabaseLocked(boolean writable) {
if (mDatabase != null) {
if (!mDatabase.isOpen()) {
// Darn! The user closed the database by calling mDatabase.close().
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// The database is already open for business.
return mDatabase;
}
}
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
SQLiteDatabase db = mDatabase;
try {
mIsInitializing = true;
if (db != null) {
if (writable && db.isReadOnly()) {
db.reopenReadWrite();
}
} else if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
try {
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}
onConfigure(db);
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
db.beginTransaction();
try {
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
if (db.isReadOnly()) {
Log.w(TAG, "Opened " + mName + " in read-only mode");
}
mDatabase = db;
return db;
} finally {
mIsInitializing = false;
if (db != null && db != mDatabase) {
db.close();
}
}
}
~~~
对于getReadableDatabase()的注释,大致意思也就是:
getWritableDatabase()和getReadableDatabase()会返回相同的对象,除非出现了一些如空间已满的问题,这时就会返回一个只读的对象。当问题解决了之后,只读对象将会被关闭,这时就会返回一个可读写的对象。
SQL实例可执行代码:
[http://download.csdn.net/detail/tangnengwu/7369503](http://download.csdn.net/detail/tangnengwu/7369503)