android数据存储之SQLite(个人日记本)
Android中通过SQLite数据库引擎来实现结构化数据存储。SQLite是一个嵌入式数据库引擎,针对内存等资源有限的设备(如手机、PDA、MP3)提供的一种高效的数据库引擎。
SQLite数据库不像其他的数据库(如Oracle),它没有服务器进程。所有的内容包含在同一个单文件中。该文件是跨平台的,可以自由复制。基于其自身的先天优势,SQLite在嵌入式领域得到广泛应用。
SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。
但如何利用SQLite来开发数据库应用呢?我们如何才能实现在用户初次使用或升级软件时自动在用户的手机上创建出应用需要的数据库表呢?为了解决这一问题,在Android系统,为我们提供了一个名为SQLiteOpenHelper的抽象类,必须继承它才能使用。
SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2。
下面就以个人日记本为例来更好地学习SQLite...
首先展示一下层次结构,项目的命名、包及其类的命名:
阶段一:新建Android项目,命名为MyDiary .然后使用SQLiteOpenHelper(抽象类)来完成数据库的创建.新建DBHelper类,让它继承SQLiteOpenHelper类,具体代码如下:
import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;public class DBHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "diary.db";private static final int DATABASE_VERSION = 1;public DBHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("create table diary(_id integer primary key autoincrement,title varchar(20),content varchar(1000),pubdate)");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}
阶段二:配置好单元测试的环境:
<uses-library android:name="android.test.runner" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.lks.mydiary" >
</instrumentation>
然后进行单元测试:看数据库究竟有没有被创建出来..
package com.lks.mydiary.test;import java.text.SimpleDateFormat;import java.util.Date;import com.lks.mydiary.entity.Diary;import com.lks.mydiary.service.DBHelper;import com.lks.mydiary.service.DiaryService;import android.test.AndroidTestCase;public class DiaryServiceTest extends AndroidTestCase {public void testOncreate() {DBHelper dbHelper = new DBHelper(getContext());dbHelper.getWritableDatabase();}}
执行单元测试,创建好的数据库是以文件的形式进行存放的...
进入DDMS观察存放位置:data/data/应用的包名/databases/diary.db
如何观察数据库中建立的表呢?
打开数据库:借助于第三方工具SQLiteDeveloper(注册数据库)
导出数据库后,借助于第三方工具注册数据库
阶段三:定义实体类Diary类.
package com.lks.mydiary.entity;public class Diary {private Integer id;private String title;private String content;private String pubdate;public Diary(String title, String content, String pubdate) {super();this.title = title;this.content = content;this.pubdate = pubdate;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getPubdate() {return pubdate;}public void setPubdate(String pubdate) {this.pubdate = pubdate;}}
阶段四:定义数据库访问类DiaryService类,搭建框架.
package com.lks.mydiary.service;import java.util.ArrayList;import java.util.List;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import com.lks.mydiary.entity.Diary;public class DiaryService {private SQLiteDatabase sqLiteDatabase;private DBHelper dbHelper;public DiaryService(Context context) {dbHelper = new DBHelper(context);} /* * 保存日记 */public void save(Diary diary) {sqLiteDatabase = dbHelper.getWritableDatabase();String sql = "insert into diary(title,content,pubdate) values(?,?,?)";sqLiteDatabase.execSQL(sql,new String[] { diary.getTitle(), diary.getContent(),diary.getPubdate() });} /* * 更新日记 */public void update(Diary diary){sqLiteDatabase = dbHelper.getWritableDatabase();String sql = "update diary set title=?,content=?,pubdate=? where _id=?";sqLiteDatabase.execSQL(sql,new Object[] { diary.getTitle(), diary.getContent(),diary.getPubdate(), diary.getId()});}/* * 根据id删除日记 */public void delete(Integer id) {sqLiteDatabase = dbHelper.getWritableDatabase();// 得到的是同一个数据库实例sqLiteDatabase.execSQL("delete from diary where _id=?",new Object[]{id});}/* * 根据id查询日记 */public Diary find(Integer id) {Diary diary = null;sqLiteDatabase = dbHelper.getReadableDatabase();// 得到游标,最多只有一条数据Cursor cursor = sqLiteDatabase.rawQuery("select * from diary where _id=?",new String[] { id.toString() });// 如果移动成功就代表存在if (cursor.moveToFirst()) {// 只能根据列的索引来获得相应的字段值String title = cursor.getString(cursor.getColumnIndex("title"));String content = cursor.getString(cursor.getColumnIndex("content"));String pubdate = cursor.getString(cursor.getColumnIndex("pubdate"));diary = new Diary(title, content, pubdate);}return diary;}/* * 分页查询 */public List<Diary> getDiariesByPage(Integer offset, Integer maxResult) {Diary diary = null;List<Diary> diaryList = new ArrayList<Diary>();sqLiteDatabase = dbHelper.getReadableDatabase();// 得到游标,最多只有一条数据Cursor cursor = sqLiteDatabase.rawQuery("select * from diary limit ?,?",new String[] { offset.toString(), maxResult.toString() });while (cursor.moveToNext()) {String title = cursor.getString(cursor.getColumnIndex("title"));String content = cursor.getString(cursor.getColumnIndex("content"));String pubdate = cursor.getString(cursor.getColumnIndex("pubdate"));diary = new Diary(title, content, pubdate);diaryList.add(diary);}cursor.close();return diaryList; } /* * 获取所有日记 */public Cursor getAllDiaries(){sqLiteDatabase=dbHelper.getReadableDatabase();Cursor cursor=sqLiteDatabase.rawQuery("select * from diary", null);return cursor;} /* * 获取记录总数 */public long count() {long count=0;sqLiteDatabase=dbHelper.getReadableDatabase();Cursor cursor=sqLiteDatabase.rawQuery("select count(*) from diary ",null);cursor.moveToFirst();count=cursor.getLong(0);return count;}}
阶段五:界面和功能设计。当运行程序,主界面显示日志列表。当没有日记时显示“你好懒,还没开始写日记呢”,如下图:
具体代码如下:
activity_diary.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/bg" > <ListView android:id="@id/android:list" android:layout_width="wrap_content" android:layout_height="wrap_content" > </ListView> <TextView android:id="@id/android:empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="你好懒,还没开始写日记呢"/></LinearLayout>
item_diary.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" /> <TextView android:id="@+id/pubdate" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right" android:padding="10dp" /></LinearLayout>
当点击菜单键时,会弹出菜单:
当点击“添加一篇日记”,跳转至另一页面SaveActivity.
具体代码如下:
activity_save.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/bg" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/title" /> <EditText android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/content" /> <EditText android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:minLines="6" /> <Button android:id="@+id/save" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/save" /></LinearLayout>
填写好标题和内容,保存之后页面自动跳转到显示日志列表的主界面。可以点击某一篇日记进行查看,同时进行编辑修改。
当选中某篇日记,点击菜单中的删除日记按钮可以删除当前选中的日记。
阶段六:编辑Activity,进行对个人日记本增删改查的功能实现。具体代码如下:
DiaryActivity.java:
package com.lks.mydiary;import com.lks.mydiary.entity.Diary;import com.lks.mydiary.service.DiaryService;import android.os.Bundle;import android.app.AlertDialog;import android.app.ListActivity;import android.content.DialogInterface;import android.content.DialogInterface.OnClickListener;import android.content.Intent;import android.database.Cursor;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.AdapterView.OnItemSelectedListener;import android.support.v4.widget.SimpleCursorAdapter;public class DiaryActivity extends ListActivity {private DiaryService diaryService;private int idSelect;public static final int MENU_INSERT = 0;// 关于菜单public static final int MENU_DELETE = 1;// 退出菜单@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_diary);refreshList();//点击事件,当点击某篇日记时..getListView().setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> adapter, View view,int position, long id) {Intent intent = new Intent();intent.putExtra("button", "find");intent.setClass(DiaryActivity.this, SaveActivity.class);Bundle bundle = new Bundle();Diary diary = diaryService.find((int) id);bundle.putString("title", diary.getTitle());bundle.putString("content", diary.getContent());bundle.putInt("id", (int)id);intent.putExtras(bundle);startActivity(intent);}});getListView().setOnItemSelectedListener(new OnItemSelectedListener() {public void onItemSelected(AdapterView<?> adapterView, View view,int position, long id) {idSelect = (int) id;}public void onNothingSelected(AdapterView<?> arg0) {}});}private void refreshList() {diaryService = new DiaryService(this);Cursor cursor = diaryService.getAllDiaries();startManagingCursor(cursor);SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(this,R.layout.item_diary, cursor, new String[] { "title", "pubdate" },new int[] { R.id.title, R.id.pubdate });setListAdapter(simpleCursorAdapter);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {menu.add(0, MENU_INSERT, 0, R.string.insert);// 第一个参数为组号,便于对整个组进行操作;第二个参数为菜单的ID,为了标识菜单项;第三个参数为显示顺序menu.add(0, MENU_DELETE, 1, R.string.delete);return true;}/** * 当点击菜单项时调用此方法 */@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int itemId = item.getItemId();// 获取菜单项的唯一编号switch (itemId) {//添加日记case MENU_INSERT:Intent intent = new Intent();intent.putExtra("button", "insert");intent.setClass(DiaryActivity.this, SaveActivity.class);startActivity(intent);break;//删除日记case MENU_DELETE:AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setIcon(android.R.drawable.ic_menu_delete).setTitle(R.string.delete).setMessage(R.string.info).setPositiveButton(R.string.ok, new OnClickListener() {public void onClick(DialogInterface dialog, int which) {diaryService = new DiaryService(DiaryActivity.this);diaryService.delete(idSelect);refreshList();}}).setNegativeButton(R.string.cancel, new OnClickListener() {public void onClick(DialogInterface dialog, int which) {}}).create().show();break;default:break;}return true;}}
SaveActivity.java:
package com.lks.mydiary;import java.text.SimpleDateFormat;import java.util.Date;import com.lks.mydiary.entity.Diary;import com.lks.mydiary.service.DiaryService;import android.os.Bundle;import android.app.Activity;import android.content.Intent;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;import android.widget.Toast;public class SaveActivity extends Activity {private EditText titleText;private EditText contentText;private Button save;private DiaryService diaryService;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_save);titleText = (EditText) this.findViewById(R.id.title);contentText = (EditText) this.findViewById(R.id.content);save = (Button) this.findViewById(R.id.save);Intent intent = this.getIntent();String msg = intent.getStringExtra("button");//实现添加日记if (msg.equals("insert")) {save.setOnClickListener(new OnClickListener() {public void onClick(View v) {Diary diary = new Diary(titleText.getText().toString(),contentText.getText().toString(),getCurrentTime(new Date()));diaryService = new DiaryService(SaveActivity.this);diaryService.save(diary);Intent intent=new Intent();intent.setClass(SaveActivity.this, DiaryActivity.class);startActivity(intent);Toast.makeText(SaveActivity.this, R.string.save_success,Toast.LENGTH_LONG).show();}});//实现修改日记} else if (msg.equals("find")) {final Bundle bundle = this.getIntent().getExtras();if (bundle != null) {String title = bundle.getString("title");String content = bundle.getString("content");if (titleText != null) {titleText.setText(title);}if (contentText != null) {contentText.setText(content);}}save.setOnClickListener(new OnClickListener() {public void onClick(View v) {Diary diary = new Diary(titleText.getText().toString(),contentText.getText().toString(),getCurrentTime(new Date()));diary.setId(bundle.getInt("id"));diaryService = new DiaryService(SaveActivity.this);diaryService.update(diary);Intent intent = new Intent(SaveActivity.this,DiaryActivity.class);startActivity(intent);Toast.makeText(SaveActivity.this, R.string.update_success,Toast.LENGTH_LONG).show();}});}}public String getCurrentTime(Date date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日hh时mm分ss秒");return simpleDateFormat.format(date);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_save, menu);return true;}}
这样,个人日记本的小项目就完成啦~对应的完成的项目已上传到资源~欢迎下载~