Android提供了4种数据存储技术,分别是SharedPreferences、Files、SQLite数据库和网络存储数据。(有的开发者认为使用ContentProvider也可以算是一种,但我觉得ContentProvider本质上还是用的sqlite,所以未将其纳入其中)
其中最常用的有这三种:SharedPreferences、Files、SQLite数据库。
下面我们分别来认识一下:
1、SharedPreferences
它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。
其存储位置在/data/data/<包名>/shared_prefs目录下。
SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。
它主要是通过键值对的方式来存储数据的,获取它的方式有两种:
1、getSharedPreferences():如果需要多个使用名称来区分的共享文件,则可以使用该方法,其第一个参数就是共享文件的名称。对于使用同一个名称获得的多个SharedPreferences引用,其指向同一个对象。
2、getPreferences();如果Activity仅需要一个共享文件,则可以使用该方法。因为只有一个文件,它并不需要提供名称。
完成SharedPreferences类中增加值的步骤如下:
- 调用SharedPreferences类的edit()方法获得SharedPreferences.Editor对象。
- 调用如putBoolean()、putString()等方法附加值
- 使用commit()方法提交新值。
SharedPreferences使用时,分两种:
一种是在一个项目中使用,另一个是在两个不同的项目中使用。
下面我们用实例来演示一下,首先是第一种情况(即在一个项目中使用):
首先是布局文件main.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <LinearLayout 7 android:layout_width="match_parent" 8 android:layout_height="wrap_content"> 9 <TextView 10 android:id="@+id/name_tv" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="姓名:" 14 android:textSize="30sp"/> 15 <EditText 16 android:id="@+id/ET_name" 17 android:layout_width="0dip" 18 android:layout_height="wrap_content" 19 android:layout_weight="1" 20 android:inputType="text" 21 android:textSize="20sp"> 22 <requestFocus></requestFocus> 23 </EditText> 24 </LinearLayout> 25 <LinearLayout 26 android:layout_width="match_parent" 27 android:layout_height="wrap_content"> 28 <TextView 29 android:id="@+id/tv_psd" 30 android:layout_height="wrap_content" 31 android:layout_width="wrap_content" 32 android:text="密码:" 33 android:textSize="30sp"/> 34 <EditText 35 android:id="@+id/et_psd" 36 android:layout_weight="1" 37 android:layout_height="wrap_content" 38 android:layout_width="0dip" 39 android:textSize="20sp" 40 android:inputType="textPassword"/> 41 </LinearLayout> 42 <Button 43 android:id="@+id/bt_login" 44 android:layout_height="wrap_content" 45 android:layout_width="wrap_content" 46 android:text="登陆" 47 android:textSize="20sp"/> 48 </LinearLayout>
read_data.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tv_rname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp"/> <TextView android:id="@+id/tv_rpsd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp"/> </LinearLayout>
然后新建两个Activity,分别为ReadActivity和WriteActivity:
1 public class ReadActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 // TODO Auto-generated method stub 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.read_data); 8 TextView tv_name=(TextView) findViewById(R.id.tv_rname); 9 TextView tv_psd=(TextView) findViewById(R.id.tv_rpsd); 10 SharedPreferences sp=getSharedPreferences("test", MODE_PRIVATE); 11 tv_name.setText(sp.getString("name", "error_name")); 12 tv_psd.setText(sp.getString("psd", "error_psd")); 13 } 14 15 }
1 public class WriteActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 // TODO Auto-generated method stub 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.main); 8 final EditText et_name=(EditText) findViewById(R.id.ET_name); 9 final EditText et_psd=(EditText) findViewById(R.id.et_psd); 10 Button bt_login=(Button) findViewById(R.id.bt_login); 11 bt_login.setOnClickListener(new OnClickListener() { 12 13 @Override 14 public void onClick(View v) { 15 String name=et_name.getText().toString(); 16 String psd=et_psd.getText().toString(); 17 SharedPreferences sp_login=getSharedPreferences("test", MODE_PRIVATE); 18 Editor editor=sp_login.edit(); 19 editor.putString("name", name); 20 editor.putString("psd", psd); 21 editor.commit(); 22 Intent intent=new Intent(); 23 intent.setClass(WriteActivity.this, ReadActivity.class); 24 startActivity(intent); 25 26 } 27 }); 28 } 29 }
这里记得把配置文件也要修改一下(注册Activity和修改默认启动Activity):
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.demo_base_sharedpreferences" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="14" 9 android:targetSdkVersion="19" /> 10 11 <application 12 android:allowBackup="true" 13 android:icon="@drawable/ic_launcher" 14 android:label="@string/app_name" 15 android:theme="@style/AppTheme" > 16 <activity 17 android:name="com.example.demo_base_sharedpreferences.WriteActivity" 18 android:label="@string/app_name" > 19 <intent-filter> 20 <action android:name="android.intent.action.MAIN" /> 21 22 <category android:name="android.intent.category.LAUNCHER" /> 23 </intent-filter> 24 </activity> 25 <activity android:name="com.example.demo_base_sharedpreferences.ReadActivity"></activity> 26 </application> 27 28 </manifest>
代码完毕,运行程序即可体验SharedPreferences在仅在一个项目中的使用情况。
下面来看看第二种(两个不同项目之间的使用),因为很多代码都是相同的,就直接上代码了:
创建第一个项目demo_between_SharedPreferences01
main布局文件代码:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <LinearLayout 7 android:layout_height="wrap_content" 8 android:layout_width="match_parent"> 9 <TextView 10 android:id="@+id/tv_read" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="全局可读:" 14 android:textSize="20sp"/> 15 <EditText 16 android:id="@+id/et_read" 17 android:layout_width="0dip" 18 android:layout_height="wrap_content" 19 android:layout_weight="1" 20 android:inputType="text" 21 android:textSize="20sp"/> 22 </LinearLayout> 23 <LinearLayout 24 android:layout_height="wrap_content" 25 android:layout_width="match_parent"> 26 <TextView 27 android:id="@+id/tv_write" 28 android:layout_width="wrap_content" 29 android:layout_height="wrap_content" 30 android:text="全局可写:" 31 android:textSize="20sp"/> 32 <EditText 33 android:id="@+id/et_write" 34 android:layout_width="0dip" 35 android:layout_height="wrap_content" 36 android:layout_weight="1" 37 android:inputType="text" 38 android:textSize="20sp"/> 39 </LinearLayout> 40 <LinearLayout 41 android:layout_height="wrap_content" 42 android:layout_width="match_parent"> 43 <TextView 44 android:id="@+id/tv_read_write" 45 android:layout_width="wrap_content" 46 android:layout_height="wrap_content" 47 android:text="全局可读:" 48 android:textSize="20sp"/> 49 <EditText 50 android:id="@+id/et_read_write" 51 android:layout_width="0dip" 52 android:layout_height="wrap_content" 53 android:layout_weight="1" 54 android:inputType="text" 55 android:textSize="20sp"/> 56 </LinearLayout> 57 <Button 58 android:id="@+id/bt_save" 59 android:layout_width="wrap_content" 60 android:layout_height="wrap_content" 61 android:text="保存键值对" 62 android:textSize="20sp"/> 63 </LinearLayout>
java文件:
1 private EditText et_read,et_write,et_read_write; 2 private SharedPreferences sp_read,sp_write,sp_read_write; 3 4 @SuppressLint("WorldReadableFiles") 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.main); 9 et_read=(EditText) findViewById(R.id.et_read); 10 et_write=(EditText) findViewById(R.id.et_write); 11 et_read_write=(EditText) findViewById(R.id.et_read_write); 12 sp_read=getSharedPreferences("read", MODE_WORLD_READABLE); 13 sp_write=getSharedPreferences("write", MODE_WORLD_WRITEABLE); 14 sp_read_write=getSharedPreferences("read_write", MODE_WORLD_READABLE+MODE_WORLD_WRITEABLE); 15 Button bt_save=(Button) findViewById(R.id.bt_save); 16 bt_save.setOnClickListener( save); 17 } 18 19 public OnClickListener save=new OnClickListener() { 20 21 @Override 22 public void onClick(View v) { 23 Editor ed_read=sp_read.edit(); 24 Editor ed_write=sp_write.edit(); 25 Editor ed_read_write=sp_read_write.edit(); 26 ed_read.putString("test", et_read.getText().toString()); 27 ed_write.putString("test", et_write.getText().toString()); 28 ed_read_write.putString("test", et_read_write.getText().toString()); 29 ed_read.commit(); 30 ed_write.commit(); 31 ed_read_write.commit(); 32 33 } 34 };
创建第二个项目demo_between_SharedPreferences02
main.xml布局文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 <TextView 7 android:id="@+id/read" 8 android:layout_height="wrap_content" 9 android:layout_width="wrap_content" 10 android:textSize="30sp"/> 11 <TextView 12 android:id="@+id/write" 13 android:layout_height="wrap_content" 14 android:layout_width="wrap_content" 15 android:textSize="30sp"/> 16 <TextView 17 android:id="@+id/read_write" 18 android:layout_height="wrap_content" 19 android:layout_width="wrap_content" 20 android:textSize="30sp"/> 21 22 </LinearLayout>
java文件
1 private SharedPreferences sp_read,sp_write,sp_read_write; 2 private TextView tv_read,tv_write,tv_read_write; 3 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.main); 8 tv_read=(TextView) findViewById(R.id.read); 9 tv_write=(TextView) findViewById(R.id.write); 10 tv_read_write=(TextView) findViewById(R.id.read_write); 11 Context othercontext=null; 12 try { 13 othercontext=createPackageContext("com.example.demo_between_sharepreferences", MODE_PRIVATE); 14 } catch (NameNotFoundException e) { 15 // TODO Auto-generated catch block 16 e.printStackTrace(); 17 } 18 sp_read=othercontext.getSharedPreferences("read", MODE_WORLD_READABLE); 19 sp_write=othercontext.getSharedPreferences("write", MODE_WORLD_WRITEABLE); 20 sp_read_write=othercontext.getSharedPreferences("read_write", MODE_WORLD_READABLE+MODE_WORLD_WRITEABLE); 21 tv_read.setText("全局可读:"+sp_read.getString("test", "null")); 22 tv_write.setText("全局可写:"+sp_write.getString("test", "null")); 23 tv_read_write.setText("全局可读可写:"+sp_read_write.getString("test", "null")); 24 25 }
然后运行第一个项目,输入信息,点击保存。
运行第二个项目。则界面上显示了用户刚刚在第一个项目中输入并保存的信息。
2、文件Files对象存储
在Android中,文件对象存储主要有两种方式:
- java提供的io流体系。(FileOutputStream类的openFileOutput()方法和FileInputStram类提供的openFileInput()方法)默认情况下,使用IO流保存的文件仅对当前应用程序可见。如果用户卸载了该应用程序,则保存数据的文件也会被一起删除。
- 使用Environment类的getExternalStorageDirectory()方法对Android中SD卡的操作。
对文件的操作呢,建议大家可以先看看它的相关文档,如我们会使用到的:
http://developer.android.com/intl/zh-cn/reference/java/io/File.html
接下来我们依然用实例来体验一下吧。
第一种使用java提供的io流体系
本实例的布局文件我们使用讲SharedPreferences的第一种情况时使用的布局文件。(注意:在控件的名称上可能会有改动)
然后创建两个Activity:InternalDataWriteActivity和InternalDataReadActivity:
1 public class InternalDataReadActivity extends Activity { 2 3 protected void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); // 调用父类方法 5 setContentView(R.layout.result);// 使用布局文件 6 FileInputStream fis = null; 7 byte[] buffer = null; 8 try { 9 fis = openFileInput("login");// 获得文件输入流 10 buffer = new byte[fis.available()];// 定义保存数据的数组 11 fis.read(buffer);// 从输入流中读取数据 12 } catch (FileNotFoundException e) { 13 e.printStackTrace(); 14 } catch (IOException e) { 15 e.printStackTrace(); 16 } finally { 17 if (fis != null) { 18 try { 19 fis.close();// 关闭文件输入流 20 } catch (IOException e) { 21 e.printStackTrace(); 22 } 23 } 24 } 25 26 TextView usernameTV = (TextView) findViewById(R.id.username); 27 TextView passwordTV = (TextView) findViewById(R.id.password); 28 String data = new String(buffer);// 获得数组中保存的数据 29 String username = data.split(" ")[0];// 获得username 30 String password = data.split(" ")[1];// 获得password 31 usernameTV.setText("用户名:" + username);// 显示用户名 32 passwordTV.setText("密 码:" + password);// 显示密码 33 } 34 }
1 public class InternalDataWriteActivity extends Activity { 2 /** Called when the activity is first created. */ 3 @Override 4 public void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState);// 调用父类方法 6 setContentView(R.layout.main);// 应用布局文件 7 final EditText usernameET = (EditText) findViewById(R.id.username);// 获得用户名控件 8 final EditText passwordET = (EditText) findViewById(R.id.password);// 获得密码控件 9 Button login = (Button) findViewById(R.id.login);// 获得按钮控件 10 login.setOnClickListener(new View.OnClickListener() { 11 12 @Override 13 public void onClick(View v) { 14 String username = usernameET.getText().toString();// 获得用户名 15 String password = passwordET.getText().toString();// 获得密码 16 FileOutputStream fos = null; 17 try { 18 fos = openFileOutput("login", MODE_PRIVATE);// 获得文件输出流 19 fos.write((username + " " + password).getBytes());// 保存用户名和密码 20 fos.flush();// 清除缓存 21 } catch (FileNotFoundException e) { 22 e.printStackTrace(); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } finally { 26 if (fos != null) { 27 try { 28 fos.close();// 关闭文件输出流 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 } 33 } 34 Intent intent = new Intent();// 创建Intent对象 35 intent.setClass(InternalDataWriteActivity.this, InternalDataReadActivity.class);// 指定跳转到InternalDataReadActivity 36 startActivity(intent);// 实现跳转 37 } 38 }); 39 } 40 }
最后注意配置文件的修改:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.mingrisoft" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk android:minSdkVersion="15" /> 8 9 <application 10 android:icon="@drawable/ic_launcher" 11 android:label="@string/app_name" > 12 <activity 13 android:name="com.mingrisoft.InternalDataWriteActivity" 14 android:label="@string/app_name" > 15 <intent-filter> 16 <action android:name="android.intent.action.MAIN" /> 17 18 <category android:name="android.intent.category.LAUNCHER" /> 19 </intent-filter> 20 </activity> 21 <activity android:name="com.mingrisoft.InternalDataReadActivity" /> 22 </application> 23 24 </manifest>
运行程序,输入数据后,跳转到另一个页面时读取第一个页面的数据。(当然,这种效果也可以使用SharedPreferences)
第二种对安卓的SD卡的操作
修改main.xml布局文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:background="@drawable/background" 6 android:orientation="vertical" > 7 8 <TextView 9 android:id="@+id/message" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" 12 android:textColor="@android:color/white" 13 android:textSize="20dp" /> 14 15 </LinearLayout>
然后创建一个Activity类:
1 public class FileCreateActivity extends Activity { 2 /** Called when the activity is first created. */ 3 @Override 4 public void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState);// 调用父类方法 6 setContentView(R.layout.main);// 应用布局文件 7 TextView tv = (TextView) findViewById(R.id.message); 8 File root = Environment.getExternalStorageDirectory();// 获得SD卡根路径 9 if(root.exists()&&root.canWrite()){ 10 File file = new File(root, "DemoFile.txt"); 11 try { 12 if (file.createNewFile()) { 13 tv.setText(file.getName() + "创建成功!"); 14 } else { 15 if(file.exists()){ 16 file.delete(); 17 tv.setText("已删除同名文件,请重新创建。"); 18 } 19 else 20 tv.setText(file.getName() + "创建失败!"); 21 22 } 23 24 } catch (IOException e) { 25 e.printStackTrace(); 26 } 27 }else { 28 tv.setText("SD卡不存在或者不可写!"); 29 } 30 } 31 }
最后在配置文件中添加权限和修改默认Activity:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<activity
android:name="com.mingrisoft.FileCreateActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
此时,即可运行程序。
3、SQLite的数据库存储
Android系统自带有轻量级的数据库—SQLite。它与我们所接触其他数据库大部分都相同,支持大部分的标准SQL语句,分页查询和mysql相同:
select * from person(表名) LIMIT 10,20(第10条索引开始,取20条数据)。
另外,它还有个需要注意的地方,那就是不区分数据类型(主键除外)。
光说知识点比较空洞,下面我们用一个例子来认识sqlite,在例子中会用注释来解释一些sqlite的知识。
不多说直接上代码:
新建一个DBOpenHelper类,并继承SQLiteOpenHelper:
1 package cn.itcast.sqlite; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteOpenHelper; 6 7 public class DBOpenHelper extends SQLiteOpenHelper { // 定义工具类, 继承SQLiteOpenHelper 8 9 public DBOpenHelper(Context context) { // 创建对象的时候, 需要传入上下文环境 10 super(context, "itcast.db", null, 4); 11 /* 12 * 由于父类没有无参构造函数, 必须显式调用有参的构造函数 13 * 参数1: 上下文环境, 用来确定数据库文件存储的目录 14 * 参数2: 数据库文件的名字 15 * 参数3: 生成游标的工厂, 填null就是使用默认的 16 * 参数4: 数据库的版本, 从1开始 17 */ 18 } 19 20 @Override 21 public void onCreate(SQLiteDatabase db) { 22 System.out.println("onCreate"); 23 db.execSQL("CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20))"); // 执行SQL语句, 创建表 24 } 25 26 @Override 27 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 28 System.out.println("onUpgrade"); 29 db.execSQL("ALTER TABLE person ADD balance INTEGER"); 30 } 31 32 }
创建一个实体类person,接下来的例子中会使用到:
在创建时,get,set方法和一些构造函数可以通过选择菜单栏或点击鼠标右键出现的source选项中选择快速生成。
1 package cn.itcast.sqlite; 2 3 public class Person { 4 private Integer id; 5 private String name; 6 private Integer balance; 7 8 public Person() { 9 super(); 10 } 11 12 public Person(String name, Integer balance) { 13 super(); 14 this.name = name; 15 this.balance = balance; 16 } 17 18 public Person(Integer id, String name, Integer balance) { 19 super(); 20 this.id = id; 21 this.name = name; 22 this.balance = balance; 23 } 24 25 public Integer getId() { 26 return id; 27 } 28 29 public void setId(Integer id) { 30 this.id = id; 31 } 32 33 public String getName() { 34 return name; 35 } 36 37 public void setName(String name) { 38 this.name = name; 39 } 40 41 public Integer getBalance() { 42 return balance; 43 } 44 45 public void setBalance(Integer balance) { 46 this.balance = balance; 47 } 48 49 @Override 50 public String toString() { 51 return "Person [id=" + id + ", name=" + name + ", balance=" + balance + "]"; 52 } 53 54 }
下面创建一个操作sql语句的PersonDao类:
该类中,包含了最常用的sql语句,其中的注释的地方希望大家理解意思。
1 package cn.itcast.sqlite; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.Context; 7 import android.database.Cursor; 8 import android.database.sqlite.SQLiteDatabase; 9 10 public class PersonDao { 11 private DBOpenHelper helper; 12 13 public PersonDao(Context context) { 14 helper = new DBOpenHelper(context); 15 } 16 17 public void insert(Person p) { 18 SQLiteDatabase db = helper.getWritableDatabase(); // 获取数据库连接(可写的) 19 db.execSQL("INSERT INTO person(name, balance) VALUES(?, ?)", new Object[] { p.getName(), p.getBalance() }); // 执行SQL语句, 插入 20 db.close(); 21 } 22 23 public void delete(int id) { 24 SQLiteDatabase db = helper.getWritableDatabase(); 25 db.execSQL("DELETE FROM person WHERE id=?", new Object[] { id }); 26 db.close(); 27 } 28 29 public void update(Person p) { 30 SQLiteDatabase db = helper.getWritableDatabase(); 31 db.execSQL("UPDATE person SET name=?, balance=? WHERE id=?", new Object[] { p.getName(), p.getBalance(), p.getId() }); 32 db.close(); 33 } 34 35 public Person query(int id) { 36 SQLiteDatabase db = helper.getReadableDatabase(); // 获取数据库连接(可读的) 37 Cursor c = db.rawQuery("SELECT name, balance FROM person WHERE id=?", new String[] { id + "" }); // 执行SQL语句, 查询, 得到游标 38 Person p = null; 39 if (c.moveToNext()) { // 判断游标是否包含下一条记录, 如果包含将游标向后移动一位 40 String name = c.getString(c.getColumnIndex("name")); // 获取"name"字段的索引, 然后根据索引获取数据 41 int balance = c.getInt(1); // 获取1号索引上的数据 42 p = new Person(id, name, balance); 43 } 44 c.close(); 45 db.close(); 46 return p; 47 } 48 49 public List<Person> queryAll() { 50 SQLiteDatabase db = helper.getReadableDatabase(); 51 Cursor c = db.rawQuery("SELECT id, name, balance FROM person", null); 52 List<Person> persons = new ArrayList<Person>(); 53 while (c.moveToNext()) { 54 Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2)); 55 persons.add(p); 56 } 57 c.close(); 58 db.close(); 59 return persons; 60 } 61 62 public int queryCount() { 63 SQLiteDatabase db = helper.getReadableDatabase(); 64 Cursor c = db.rawQuery("SELECT COUNT(*) FROM person", null); 65 c.moveToNext(); 66 int count = c.getInt(0); 67 c.close(); 68 db.close(); 69 return count; 70 } 71 72 public List<Person> queryPage(int pageNum, int capacity) { 73 String offset = (pageNum - 1) * capacity + ""; // 偏移量 74 String len = capacity + ""; // 个数 75 SQLiteDatabase db = helper.getReadableDatabase(); 76 Cursor c = db.rawQuery("SELECT id, name, balance FROM person LIMIT ?,?", new String[]{offset , len}); 77 List<Person> persons = new ArrayList<Person>(); 78 while (c.moveToNext()) { 79 Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2)); 80 persons.add(p); 81 } 82 c.close(); 83 db.close(); 84 return persons; 85 } 86 87 }
最后,我们将用单元测试类来检验我们做得是否正确(注意,不要忘记在配置文件中注册Junit的使用(详见《Android Junit单元测试》一文)):
1 package cn.itcast.sqlite; 2 3 import java.util.List; 4 import java.util.Random; 5 6 import android.test.AndroidTestCase; 7 8 public class DBTest extends AndroidTestCase { 9 10 public void testCreateDatabase() { 11 DBOpenHelper helper = new DBOpenHelper(getContext()); 12 helper.getWritableDatabase(); 13 /* 14 * 获取可写的数据连接 15 * 数据库文件不存在时, 会创建数据库文件, 并且执行onCreate()方法 16 * 数据库文件存在, 并且版本没有改变时, 不执行任何方法 17 * 数据库文件存在, 版本提升, 执行onUpgrade()方法 18 */ 19 } 20 21 public void testInsert() { 22 PersonDao dao = new PersonDao(getContext()); 23 for (int i = 1; i <= 100; i++) 24 dao.insert(new Person("Test" + i, new Random().nextInt(10000))); 25 } 26 27 public void testDelete() { 28 PersonDao dao = new PersonDao(getContext()); 29 dao.delete(1); 30 } 31 32 public void testUpdate() { 33 PersonDao dao = new PersonDao(getContext()); 34 dao.update(new Person(3, "王五", 30000)); 35 } 36 37 public void testQuery() { 38 PersonDao dao = new PersonDao(getContext()); 39 System.out.println(dao.query(3)); 40 } 41 42 public void testQueryAll() { 43 PersonDao dao = new PersonDao(getContext()); 44 List<Person> persons = dao.queryAll(); 45 for (Person p : persons) 46 System.out.println(p); 47 } 48 49 public void testQueryCount() { 50 PersonDao dao = new PersonDao(getContext()); 51 System.out.println(dao.queryCount()); 52 } 53 54 public void testQueryPage() { 55 PersonDao dao = new PersonDao(getContext()); 56 List<Person> persons = dao.queryPage(3, 20); 57 for (Person p : persons) 58 System.out.println(p); 59 } 60 61 }
运行程序即可。(该例使用的是System.out输出结果,为方便查看建议add a new logcte filter)
上面是sqlite的最常规和最基本的操作。
下面我们来看看sqlite的一些其他操作:
1、数据库事务的操作。不多说,直接上代码:
在PersonDao类中,添加一个新的方法:(前两个参数代表的是数据库中的ID字段)
1 public void remit(int from, int to, int amount) { 2 SQLiteDatabase db = helper.getWritableDatabase(); 3 try { 4 db.beginTransaction(); // 开始事务 5 db.execSQL("UPDATE person SET balance=balance-? WHERE id=?", new Object[] { amount, from }); 6 db.execSQL("UPDATE person SET balance=balance+? WHERE id=?", new Object[] { amount, to }); 7 db.setTransactionSuccessful(); // 设置成功点, 在事务结束时, 成功点之前的操作会被提交 8 /*若此处再接下面的三行代码 9 db.execSQL("……"); //如果此行的代码出现异常,那么上面的(即前面的)两个execSQL()执行的SQL语句可以正常执行,此行和下面的execSQL()将不会被执行。 10 db.execSQL("……"); //如果只有此行代码异常,那么最上面的(即前面的)两个execSQL()执行的SQL语句可以正常执行,此行和上面的execSQL()将不会被执行。 11 db.setTransactionSuccessful(); 12 */ 13 } finally { 14 db.endTransaction(); // 结束事务, 将成功点之前的操作提交 15 db.close(); 16 } 17 }
在DBtest单元测试类中,测试刚刚添加的有关事务的方法:
1 public void testRemit() { 2 PersonDao dao = new PersonDao(getContext()); 3 dao.remit(3, 2, 1000); 4 }
2、另一种数据操作(增删查改)的方式
这种方式呢,不需要写SQL语句。但是,它的实质是转换成sql语句再执行。在某些情况下呢,对数据的操作会更加方便。
下面,我们就将PersonDao类用新的数据操作的方式来实现一下,大家可以对比一下与之前的PersonDao类的区别,其实真正关键的、不同的代码就那么几句,大部分还是相同的。
1 package cn.itcast.sqlite; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.ContentValues; 7 import android.content.Context; 8 import android.database.Cursor; 9 import android.database.sqlite.SQLiteDatabase; 10 11 public class PersonDao { 12 private DBOpenHelper helper; 13 14 public PersonDao(Context context) { 15 helper = new DBOpenHelper(context); 16 } 17 18 public void insert(Person p) { 19 SQLiteDatabase db = helper.getWritableDatabase(); // 获取数据库连接(可写的) 20 ContentValues values = new ContentValues(); // 类似于Map的容器, 键是String, 用来存放列名, 值是Object, 用来存要插入的数据 21 values.put("name", p.getName()); // 某些情况下, 程序会接收一个ContentValues参数, 这时用这种方式存储比较方便 22 values.put("balance", p.getBalance()); 23 long id = db.insert("person", null, values); // 第二个参数随便写表中的一个列名即可, 用来在想插入一条除了主键全部为空的记录时使用 24 System.out.println("插入的记录的id是: " + id); 25 db.close(); 26 } 27 28 public void delete(int id) { 29 SQLiteDatabase db = helper.getWritableDatabase(); 30 int rows = db.delete("person", "id=?", new String[] { id + "" }); 31 System.out.println("删除了" + rows + "行"); 32 db.close(); 33 } 34 35 public void update(Person p) { 36 SQLiteDatabase db = helper.getWritableDatabase(); 37 ContentValues values = new ContentValues(); 38 values.put("name", p.getName()); 39 values.put("balance", p.getBalance()); 40 int rows = db.update("person", values, "id=?", new String[] { p.getId() + "" }); 41 System.out.println("更新了" + rows + "行"); 42 db.close(); 43 } 44 45 public Person query(int id) { 46 SQLiteDatabase db = helper.getReadableDatabase(); // 获取数据库连接(可读的) 47 Cursor c = db.query("person", new String[] { "name", "balance" }, "id=?", new String[] { id + "" }, null, null, null); 48 Person p = null; 49 if (c.moveToNext()) { // 判断游标是否包含下一条记录, 如果包含将游标向后移动一位 50 String name = c.getString(c.getColumnIndex("name")); // 获取"name"字段的索引, 然后根据索引获取数据 51 int balance = c.getInt(1); // 获取1号索引上的数据 52 p = new Person(id, name, balance); 53 } 54 c.close(); 55 db.close(); 56 return p; 57 } 58 59 public List<Person> queryAll() { 60 SQLiteDatabase db = helper.getReadableDatabase(); 61 Cursor c = db.query("person", null, null, null, null, null, "id DESC"); 62 List<Person> persons = new ArrayList<Person>(); 63 while (c.moveToNext()) { 64 Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2)); 65 persons.add(p); 66 } 67 c.close(); 68 db.close(); 69 return persons; 70 } 71 72 public int queryCount() { 73 SQLiteDatabase db = helper.getReadableDatabase(); 74 Cursor c = db.query("person", new String[]{ "COUNT(*)" }, null, null, null, null, null); 75 c.moveToNext(); 76 int count = c.getInt(0); 77 c.close(); 78 db.close(); 79 return count; 80 } 81 82 public List<Person> queryPage(int pageNum, int capacity) { 83 String offset = (pageNum - 1) * capacity + ""; // 偏移量 84 String len = capacity + ""; // 个数 85 SQLiteDatabase db = helper.getReadableDatabase(); 86 Cursor c = db.query("person", null, null, null, null, null, null, offset + "," + len); 87 List<Person> persons = new ArrayList<Person>(); 88 while (c.moveToNext()) { 89 Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2)); 90 persons.add(p); 91 } 92 c.close(); 93 db.close(); 94 return persons; 95 } 96 97 public void remit(int from, int to, int amount) { 98 SQLiteDatabase db = helper.getWritableDatabase(); 99 try { 100 db.beginTransaction(); // 开始事务 101 db.execSQL("UPDATE person SET balance=balance-? WHERE id=?", new Object[] { amount, from }); 102 db.execSQL("UPDATE person SET balance=balance+? WHERE id=?", new Object[] { amount, to }); 103 db.setTransactionSuccessful(); // 设置成功点, 在事务结束时, 成功点之前的操作会被提交 104 } finally { 105 db.endTransaction(); // 结束事务, 将成功点之前的操作提交 106 db.close(); 107 } 108 } 109 110 }