SQLite的小例子--备忘录

 

1. Android Intents

1.1. Android中的SQLite

SQLite是一个嵌入在Android中的开源数据库。SQLite支持标准的关系型数据库特征,比如SQL语法,事务和预处理语句。另外它在运行时只需要很少的内存(大约250KByte)

Android中使用SQLite不需要任何数据库的安装或管理(不需要数据库管理员)。你可以指定SQL来使用数据库工作,并且数据库会为你自动管理。

Android中使用数据库工作可以减缓由于必要的I/O操作,因此它建议在AsyncTask中执行这项任务。

数据库支持的数据类型:

TEXT 类似JAVA中的String

INTEGER 类似JAVA中的long

REAL 类似JAVA中的double

在将这些数据保存到数据库之前,所有其他的类型都必须转换成这些类型。实际上SQLite本身不验证写入列中的类型定义,你可以写一个整数到字符串列上。

      如果您的应用程序创建一个数据库,这个数据库时保存在目录

”data/data/<项目包名>/databases/数据库名。这里的第一个data目录的路径就是

Environment.getDataDirectory()的返回值。Environment.getDataDirectory()通常返回SD卡中的位置

一个SQLite数据库相对于创建它的应用程序是私有的,如果你想将数据分享给其他应用程序,可以使用ContentProvider

1.2. SQLiteOpenHelper

在你的应用程序中通过使用子类SQLiteOpenHelper来创建和更新一个数据库,在这个类中,在数据库模式变化的情况下,你需要重写onCreate()方法来创建数据库和重写onUpdate()方法来更新数据库。这两种方法都需要接收一个SQLiteOpenHelper对象。

      SQLiteOpenHelper提供方法getReadableDatabase()getWriteableDatabase()方法来获得一个SQLiteDatabase对象,在对象可以允许访问数据库,而不管是在读或写的模式下。

      对于数据库的主键,你应该一直使用标识符”_id”来作为数据库主键,在Android的一些方法中最好依赖这个标准。

      SQLiteDatabase提供方法insert()update()delete()和可以直接执行SQL

execSQL()方法,对象ContentValues允许为insertupdate定义键值,键就是列,值就是该列对应的值。

1.3. SQLiteDatabaseCursor(游标)

我们可以通过创建rawQuery()方法通过接收SQL查询数据,或者通过query()方法,该方法提供了一个指定动态数据或SQLiteQueryBuilder的接口。SQLiteBuilder类似内容提供者的接口,因此通常用于ContentProvider中。查询通常返回的是一个游标(Cursor

查询方法有如下一些参数:

query(String dbName,int[] columnNames,String whereClause, String[] valuesForWhereClause, String[] groupBy, String[] having, String[] orderBy)

如果所有的参数都要选择的话,可以将那些不需要的字句设置为null,比如where的地方设置为null,当然还可以在where的地方填入其他值(如果需要的话),比如

_id=18 and summary=?”。如果需要几个值呢?你可以通过在valuesForWhereClause数据来查询。一般来说,如果不需要的话,可以填入null,比如groupby字句。

一个游标就代表查询结果。要过的元素的数量,可以使用getCount()方法。要一在单个数据行与行之间移动数据,可以通过moveToFirst()MoveToNext()方法。通过isAfterLast()方法,可以检查下面是否还有数据。

ListView中可以通过SimpleCursorAdapter适配器来直接使用游标。

2. 开始编写应用程序

2.1.  概览

下面,我们通过一个示例程序来测试,这个程序可以允许用户保持它应该做的事项。这些事项被存放在SQLite数据库中,这个应用程序包括两个Activity,一个是用来查看所有待办事项清单,一个是用户创建/维护一个特定的待办事项。这两个Activity都是通过Intent来进行沟通的。

2.2. 工程

创建功能,名字为SQLiteTest,这里有两个Activity,一个视图用来显示待办事件列表,另一个用来编辑待办事件

2.3.数据库处理

数据库帮手:MySQLiteOpenHelper.java

 

package com.loulijun.sqlitetest;

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

public class MySQLiteOpenHelper extends SQLiteOpenHelper {
	private static final String DATABASE_NAME = "hualang";
	private static final int DATABASE_VERSION = 1;
	//数据库创建语句
	private static final String DATABASE_CREATE = 
			"create table test(_id integer primary key autoincrement, "+
			"category text not null, summary text not null, description text not null);";
	public MySQLiteOpenHelper(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(MySQLiteOpenHelper.class.getName(), "upgrading database from version "+
				oldVersion + " to " + newVersion + ", which will destroy all old data");
		db.execSQL("DROP TABLE IF EXISTS test");
		onCreate(db);
	}

}

  在上面这个助手的基础上,我们可以写类"MyAdapter"。用之来提供查询,创建,更新等功能。通过助手类的open()方法打开数据库。在更新和创建值的时候,可以使用"android.content.ContentValues"类,这个类可以存储键值对,你可以使用列名作为ContentValues的键。

 

package com.loulijun.sqlitetest;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

public class MyAdapter {
	public static final String KEY_ROWID = "_id";
	public static final String KEY_CATEGORY = "category";
	public static final String KEY_SUMMARY = "summary";
	public static final String KEY_DESCRIPTION = "description";
	public static final String DATABASE_TABLE = "test";
	private Context context;
	private SQLiteDatabase db;
	private MySQLiteOpenHelper dbHelper;
	
	public MyAdapter(Context context)
	{
		this.context = context;
	}
	
	public MyAdapter open() throws SQLException
	{
		dbHelper = new MySQLiteOpenHelper(context);
		db = dbHelper.getWritableDatabase();
		return this;
	}
	
	public void close()
	{
		dbHelper.close();
	}
	/**
	 * 创建一个新的标test,如果test成功创建则返回一个新的列id,否则返回-1来表示失败
	 */
	public long createTest(String category, String summary, String description)
	{
		ContentValues initialValues = createContentValues(category, summary, description);
		return db.insert(DATABASE_TABLE, null, initialValues);
	}
	//更新表test
	public boolean updateTest(long rowId, String category, String summary, String description)
	{
		ContentValues updateValues = createContentValues(category, summary, description);
		return db.update(DATABASE_TABLE, updateValues, KEY_ROWID + "=" +rowId, null)>0;
	}
	//删除表test
	public boolean deleteTest(long rowId)
	{
		return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null)>0;
	}
	//返回数据库中表test的所有游标列表
	public Cursor fetchALlTests()
	{
		return db.query(DATABASE_TABLE, new String[]{KEY_ROWID,
				KEY_CATEGORY,KEY_SUMMARY,KEY_DESCRIPTION}, null, null, null, null, null);
	}
	//返回在表test中被定义的某个位置的游标
	public Cursor fetchTest(long rowId)throws SQLException
	{
		Cursor mCursor = db.query(true, DATABASE_TABLE, new String[]{KEY_ROWID,
				KEY_CATEGORY, KEY_SUMMARY, KEY_DESCRIPTION}, 
				KEY_ROWID + "=" +rowId, null, null, null,null,null);
		if(mCursor != null)
		{
			mCursor.moveToFirst();
		}
		return mCursor;
	}
	
	private ContentValues createContentValues(String category, String summary,
			String description) {
		ContentValues values = new ContentValues();
		values.put(KEY_CATEGORY, category);
		values.put(KEY_SUMMARY, summary);
		values.put(KEY_DESCRIPTION, description);
		return values;
	}
}
 

<!--[if !supportLists]-->2.4. <!--[endif]-->资源

在res/menu/目录下创建listment.xml

 

<?xml version="1.0" encoding="utf-8"?>
<menu
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/insert"
    	android:title="Insert"
    />
</menu>

  在res/values目录下,编写res/values/priority.xml

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="priorities">
    	<item>紧急</item>
    	<item>提醒</item>
    </string-array>
</resources>

strings.xml如下:

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, SQLiteTestActivity!</string>
    <string name="app_name">SQLiteTest</string>
    <string name="no_tests">目前没有保存的待办事项</string>
    <string name="menu_insert">增加事项</string>
    <string name="menu_delete">删除待办</string>
    <string name="test_summary">概要</string>
    <string name="test_description">描述</string>
    <string name="test_edit_summary">编辑概要</string>
    <string name="test_edit_description">编辑描述</string>
    <string name="test_edit_confirm">确认</string>
    <color name="lisicolor">#FFE87C</color>
    <color name="black">#000000</color>
</resources>

 

2.5. 视图

我定义了三个布局文件,一个是为列表,一个是为列表的行,一个是为记事本的主体

这是第一个布局,用户设置列表

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:baselineAligned="@color/lisicolor"
    >
    <ListView
    	android:id="@android:id/list"
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
    />
	<TextView  
		android:id="@android:id/empty"
	    android:layout_width="wrap_content" 
	    android:layout_height="wrap_content" 
	    android:text="@string/no_tests"
	    />
</LinearLayout>

  这是第二个布局,用于设置列表的每一行的布局

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_height="wrap_content" android:layout_width="fill_parent"
	android:background="@color/lisicolor">
	<ImageView android:id="@+id/icon" android:src="@drawable/hualang"
		android:layout_marginLeft="4px" android:layout_marginRight="8px"
		android:layout_height="40px" android:layout_marginTop="8px"
		android:layout_width="30px">
	</ImageView>
	<TextView 
		android:text="@+id/TextView01" 
		android:layout_height="wrap_content"
	 	android:id="@+id/label"
		android:textSize="40px"
		android:layout_marginTop="6px" 
		android:layout_width="fill_parent" 
		android:textColor="@color/black">
	</TextView>
</LinearLayout>

下面是备忘录的编辑布局

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent" android:background="@color/lisicolor">


	<Spinner android:id="@+id/category" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:entries="@array/priorities"></Spinner>
	<LinearLayout android:id="@+id/LinearLayout01"
		android:layout_height="wrap_content" android:layout_width="fill_parent">
		<EditText android:layout_height="wrap_content" android:id="@+id/todo_edit_summary"
			android:layout_weight="1" android:layout_width="wrap_content"
			android:hint="Summary"></EditText>

	</LinearLayout>


	<EditText android:layout_width="fill_parent"
		android:layout_height="fill_parent" android:layout_weight="1"
		android:id="@+id/todo_edit_description" android:hint="Description" android:gravity="top"></EditText>
	<Button android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:id="@+id/todo_edit_button"
		android:text="@string/test_edit_confirm"></Button>


</LinearLayout>	

 

下面的是两个Activity的代码

SQLiteOverView.java

 

package com.loulijun.sqlitetest;

import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

public class SQLiteOverView extends ListActivity {
    private MyAdapter dbHelper;
    private static final int ACTIVITY_CREATE = 0;
    private static final int ACTIVITY_EDIT = 1;
    private static final int DELETE_ID = Menu.FIRST + 1;
    private Cursor cursor;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_list);
        this.getListView().setDividerHeight(2);
        dbHelper = new MyAdapter(this);
        dbHelper.open();
        fillData();
        registerForContextMenu(getListView());
    }
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.listmenu, menu);
		return true;
	}
	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch(item.getItemId())
		{
		case R.id.insert:
			createTest();
			return true;
		}
		return super.onMenuItemSelected(featureId, item);
	}
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch(item.getItemId())
		{
		case R.id.insert:
			createTest();
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		switch(item.getItemId())
		{
		case DELETE_ID:
			AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
			dbHelper.deleteTest(info.id);
			fillData();
			return true;
		}
		return super.onContextItemSelected(item);
	}
	
	public void createTest()
	{
		Intent i = new Intent(this,TestDetails.class);
		startActivityForResult(i, ACTIVITY_CREATE);
	}
	
		// ListView 和 view (row) on 被点击
		@Override
		protected void onListItemClick(ListView l, View v, int position, long id) {
			super.onListItemClick(l, v, position, id);
			Intent i = new Intent(this, TestDetails.class);
			i.putExtra(MyAdapter.KEY_ROWID, id);
			// Activity返回一个结果给startActivityForResult
			startActivityForResult(i, ACTIVITY_EDIT);
		}

		/**
		 * 根据其他的Activity的结果被调用
		 * requestCode是发送到Activity的原始码
		 * resutCode是返回码,0表示一切OK
		 */
		@Override
		protected void onActivityResult(int requestCode, int resultCode,
				Intent intent) {
			super.onActivityResult(requestCode, resultCode, intent);
			fillData();

		}

		private void fillData() {
			cursor = dbHelper.fetchALlTests();
			startManagingCursor(cursor);

			String[] from = new String[] { MyAdapter.KEY_SUMMARY };
			int[] to = new int[] { R.id.label };
			//现在创建一个数组适配器并且设置它现在在我们的列中
			SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
					R.layout.test_row, cursor, from, to);
			setListAdapter(notes);
		}

		@Override
		public void onCreateContextMenu(ContextMenu menu, View v,
				ContextMenuInfo menuInfo) {
			super.onCreateContextMenu(menu, v, menuInfo);
			menu.add(0, DELETE_ID, 0, R.string.menu_delete);
		}
		
		@Override
		protected void onDestroy() {
			super.onDestroy();
			if (dbHelper != null) {
				dbHelper.close();
			}
		}
	}

  TestDetails.java

 

package com.loulijun.sqlitetest;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;


public class TestDetails extends Activity {
	private EditText mTitleText;
	private EditText mBodyText;
	private Long mRowId;
	private MyAdapter mDbHelper;
	private Spinner mCategory;

	@Override
	protected void onCreate(Bundle bundle) {
		super.onCreate(bundle);
		mDbHelper = new MyAdapter(this);
		mDbHelper.open();
		setContentView(R.layout.test_edit);
		mCategory = (Spinner) findViewById(R.id.category);
		mTitleText = (EditText) findViewById(R.id.todo_edit_summary);
		mBodyText = (EditText) findViewById(R.id.todo_edit_description);

		Button confirmButton = (Button) findViewById(R.id.todo_edit_button);
		mRowId = null;
		Bundle extras = getIntent().getExtras();
		mRowId = (bundle == null) ? null : (Long) bundle
				.getSerializable(MyAdapter.KEY_ROWID);
		if (extras != null) {
			mRowId = extras.getLong(MyAdapter.KEY_ROWID);
		}
		populateFields();
		confirmButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				setResult(RESULT_OK);
				finish();
			}

		});
	}

	private void populateFields() {
		if (mRowId != null) {
			Cursor todo = mDbHelper.fetchTest(mRowId);
			startManagingCursor(todo);
			String category = todo.getString(todo
					.getColumnIndexOrThrow(MyAdapter.KEY_CATEGORY));
			
			for (int i=0; i<mCategory.getCount();i++){
				
				String s = (String) mCategory.getItemAtPosition(i); 
				Log.e(null, s +" " + category);
				if (s.equalsIgnoreCase(category)){
					mCategory.setSelection(i);
				}
			}
			
			mTitleText.setText(todo.getString(todo
					.getColumnIndexOrThrow(MyAdapter.KEY_SUMMARY)));
			mBodyText.setText(todo.getString(todo
					.getColumnIndexOrThrow(MyAdapter.KEY_DESCRIPTION)));
		}
	}

	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		saveState();
		outState.putSerializable(MyAdapter.KEY_ROWID, mRowId);
	}

	@Override
	protected void onPause() {
		super.onPause();
		saveState();
	}

	@Override
	protected void onResume() {
		super.onResume();
		populateFields();
	}

	private void saveState() {
		String category = (String) mCategory.getSelectedItem();
		String summary = mTitleText.getText().toString();
		String description = mBodyText.getText().toString();
		

		if (mRowId == null) {
			long id = mDbHelper.createTest(category, summary, description);
			if (id > 0) {
				mRowId = id;
			}
		} else {
			mDbHelper.updateTest(mRowId, category, summary, description);
		}
	}
}

 还有最后一步,注册TestDetails.java

 

<activity android:name=".TestDetails"
			android:windowSoftInputMode="stateVisible|adjustResize"/>

 

2.6. 运行应用程序



 
 

注意:项目是UTF-8编码的,在windows系统中用eclipse需要将其设置为UTF-8编码

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值