• Android数据存储技术


    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类中增加值的步骤如下:

    1. 调用SharedPreferences类的edit()方法获得SharedPreferences.Editor对象。
    2. 调用如putBoolean()、putString()等方法附加值
    3. 使用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>
    View Code

    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     };
    View Code

    创建第二个项目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>
    View Code

    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     }
    View Code

    然后运行第一个项目,输入信息,点击保存。

    运行第二个项目。则界面上显示了用户刚刚在第一个项目中输入并保存的信息。

    2、文件Files对象存储

    在Android中,文件对象存储主要有两种方式:

    1. java提供的io流体系。(FileOutputStream类的openFileOutput()方法和FileInputStram类提供的openFileInput()方法)默认情况下,使用IO流保存的文件仅对当前应用程序可见。如果用户卸载了该应用程序,则保存数据的文件也会被一起删除。
    2. 使用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 }
    View Code
     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 }
    View Code

    最后注意配置文件的修改:

     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>
    View Code

    运行程序,输入数据后,跳转到另一个页面时读取第一个页面的数据。(当然,这种效果也可以使用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>
    View Code

    然后创建一个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 }
    View Code

    最后在配置文件中添加权限和修改默认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 }
    View Code

    创建一个实体类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 }
    View Code

    下面创建一个操作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 }
    View Code

    最后,我们将用单元测试类来检验我们做得是否正确(注意,不要忘记在配置文件中注册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 }
    View Code

    运行程序即可。(该例使用的是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     }
    View Code

    在DBtest单元测试类中,测试刚刚添加的有关事务的方法:

    1 public void testRemit() {
    2         PersonDao dao = new PersonDao(getContext());
    3         dao.remit(3, 2, 1000);
    4     }
    View Code

     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 }
    View Code
    作者:af74776
    文章出处:http://www.cnblogs.com/scetopcsa/
    欢迎关注微信公众号:yilu_yiyou(一路一游),一个不仅仅是代码的世界!
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    JQ库函数记忆要点
    PHP运算符:算数运算符、逻辑运算符、三目运算符、位运算符、字符串运算符。
    ThinkPHP函数详解:F方法(快速缓存方法)
    AndroidStudio项目提交(更新)到github最详细步骤
    git项目管理及fatal: remote origin already exists.解决方法
    git项目管理及fatal: remote origin already exists.解决方法
    git分支(存在意义和使用方法)
    RecyclerView
    Git Windows版本
    chmod 777 -R on existing path getting chmod: -R: No such ...
  • 原文地址:https://www.cnblogs.com/scetopcsa/p/3641855.html
Copyright © 2020-2023  润新知