Android中的数据持久化技术

Android中的数据持久化技术

一、文件存储

1、将数据存储到文件中

(1)使用Context类中提供的openFileOutput()方法,第一个参数是文件名(不包含路径),所有文件默认存储在/data/data/package name/files/目录下;第二个参数是文件操作模式,有MODE_PRIVATE和MODE_APPEND两种。

(2)openFileOutput()方法返回一个FileOutputStream对象,得到这个对象之后就可以使用Java流的方式将数据写入到文件中了。

(3)使用这个FileOutputStream对象构建一个OutputStreamWriter对象,接着使用这个OutputStreamWriter对象构建一个BufferedWriter对象,然后就可以使用这个BufferedWriter对象将文本内容写入文件了。

2、从文件中读取数据

(1)使用Context类中提供的openFileInput()方法,只接收一个参数即文件名,返回一个FileInputStream对象,再通过Java流的方式读取。

(2)使用这个FileInputStream对象构建一个InputStreamReader对象,接着使用这个InputStreamReader对象构建一个BufferedReader对象,然后通过这个BufferedReader对象进行一行行的读取,并存放在一个StringBuilder对象中,最后返回读取的内容即可。

二、SharedPreferences存储

1、将数据存储到SharedPreferences中

(1)获取SharedPreferences对象。

  • Context类中的getSharedPreferences()方法

    此方法接收两个参数,第一个是用于指定SharedPreferences文件的名称,默认存放在/data/data/package name/shared_prefs/目录下;第二个参数用于指定操作模式,目前只有MODE_PRIVATE,其余均被废弃。

  • Activity类中的getPreferences()方法

    只接收一个操作模式参数,使用这个方法是会自动将当前活动的类名作为SharedPreferences的文件名。

  • PreferenceManager类中的getDefaultSharedPreferences()方法

    这是一个静态的方法,接收一个Context参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件。

(2)调用SharedPreferences的edit()方法获取一个SharedPreferences.Editor对象。

(3)使用该Editor对象的putXxx()方法向该Editor对象中添加数据。

(4)调用Editor的apply()方法将添加的数据提交,从而完成数据存储操作。

2、从SharedPreferences中读取数据

(1)获取SharedPreferences对象。

(2)使用该SharedPreferences对象的getXxx()方法,通过键值对的形式获取SharedPreferences中存储的数据。

三、SQLite数据库存储

1、创建数据库

(1)创建数据库帮助类,继承自SQLiteOpenHelper,其中SQLiteOpenHelper抽象类有两个抽象方法,分别是onCreate()和onUpgrade(),分别实现创建、升级数据库的逻辑。帮助类的构造函数一般使用参数少的那个,该构造函数接收4个参数,第一个参数是Context,第二个是数据库名,第三个是允许我们在查询数据库的时候返回的一个自定义的Cursor,一般传入null,第四个是当前数据库的版本号,可用于对数据库进行升级操作。

(2)构建出SQLiteOpenHelper实例后,调用其getReadableDataBase()或getWritableDataBase()方法就能够创建数据库了。数据库文件存放在/data/data/package name/databases/目录下。此时重写的onCreate()方法会得到执行。

2、升级数据库

创建数据库时如果数据库已经存在,则不会执行onCreate()方法,因此不能用这种方法添加表。构建数据库帮助类时增大传入的数据库版本,在创建数据库时会回调onUpgrade()方法,可以在该方法中删除所有表,再在该方法中调用onCreate()方法,从而实现新增表。但会造成数据丢失。

MyDatabaseHelper:

package com.songzheng.databasetest;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;

/**
 * Created by make on 2017/2/18.
 */

public class MyDatabaseHelper extends SQLiteOpenHelper{

    public static final String CREATE_BOOK = "create table Book ("
            + "id integer primary key autoincrement,"
            + "author text,"
            + "price real,"
            + "pages integer,"
            + "name text)";

    public static final String CREATE_CATEGORY = "create table Category ("
            + "id integer primary key autoincrement,"
            + "category_name text,"
            + "category_code integer )";

    private Context mContext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        sqLiteDatabase.execSQL("drop table if exists Book");
        sqLiteDatabase.execSQL("drop table if exists Category");
        onCreate(sqLiteDatabase);
    }
}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private Button btCreateDatabase;

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
        btCreateDatabase = (Button) findViewById(R.id.bt_create_database);

        btCreateDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });
    }
}

3、添加数据

(1)使用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法,返回一个SQLiteDatabase对象。借助这个对象进行CRUD操作。

(2)SQLiteDatabase中有一个insert()方法,第一个参数是表名,第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值为NULL,一般用不到,直接传入null,第三个参数是一个ContentValues对象,其提供了一系列put()方法,用于向其中添加数据,只需将表中的每个列名以及相应待添加数据传入即可。

btAddData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        //开始组装第一条数据
        values.put("name", "The Da Vinci Code");
        values.put("author", "Dan Brown");
        values.put("pages", 454);
        values.put("price", 16.96);
        db.insert("Book", null, values);

        values.clear();
        //开始组装第二条数据
        values.put("name", "The Lost Symbol");
        values.put("author", "Dan Brown");
        values.put("pages", 510);
        values.put("price", 19.95);
        db.insert("Book", null, values);
    }
});

4、更新数据

同添加数据类似,SQLiteDatabase中也提供了update方法,用于对数据进行更新,这个方法接收4个参数,第一个是表名, 第二个是ContentValues对象,用于存放要更新的数据,第三、四个参数用于约束更新某一行或某几行的数据,不指定的话就是更新所有行。

btUpdateData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put("price", 10.99);
        db.update("Book", values, "name = ?", new String[]{"The Da Vinci Code"});
    }
});

5、删除数据

同添加更新类似,SQLiteDatabase同样提供了一个delete()方法,专门用于删除数据。该方法接收3个参数,第一个参数是表名,第二、三个参数是用于约束删除某一行或某几行的数据,不指定的话默认删除所有行。

btDeleteDate.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.delete("Book", "pages > ?", new String[]{"500"});
    }
});

6、查询数据

(1)同样SQLiteDatabase提供了query()方法,用于对数据进行查询。该方法接收7个参数,第一个参数是表名,第二个参数指定查询哪几列,如果不指定则默认查询所有列,第三、四个参数用于约束查询某一行或某几行的数据,不指定则默认查询所有行的数据,第五个参数用于指定需要去group by的列,不指定则表示不对查询结果进行group by操作,第六个参数用于对group by之后的数据进行进一步过滤,不指定则表示不进行过滤,第七个参数用于指定查询结果的排列方式,不指定则表示使用默认的排列方式。

(2)query()方法返回一个Cursor对象,查询到的所有数据将从这个对象中取出。

btQueryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        //查询Book表中的所有数据
        Cursor cursor = db.query("Book", null, null, null, null, null, null);
        if (cursor.moveToFirst()){
            do {
                //遍历Cursor对象,取出数据并打印
                String name = cursor.getString(cursor.getColumnIndex("name"));
                String author = cursor.getString(cursor.getColumnIndex("author"));
                int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                double price = cursor.getDouble(cursor.getColumnIndex("price"));

                Log.d("MainActivity", "book name is " + name);
                Log.d("MainActivity", "book author is " + author);
                Log.d("MainActivity", "book pages is " + pages);
                Log.d("MainActivity", "book price is " + price);
            } while (cursor.moveToNext());
        }
        cursor.close();
    }
});

7、使用SQL操作数据库

(1)通过SQLiteOpenHelper获取SQLiteDatabase。

(2)使用SQLiteDatabase的execSQL()方法通过SQL进行增改删操作,使用其rawQuery()方法通过SQL进行查询操作。

四、使用LitePal操作数据库

1、配置LitePal

(1)添加依赖

compile 'org.litepal.android:core:1.4.1'

(2)配置litepal.xml文件。在app/src/main目录下创建一个assets目录,在该目录下新建一个litepal.xml文件,编辑内容如下:

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="BookStore" ></dbname>

    <version value="1" ></version>

    <list>
    </list>
</litepal>

其中,dbname标签用于指定数据库名,version标签用于指定数据库版本号,list标签用于指定所有的映射模型。

(3)最后还需要在配置一下LitePalApplication,在AndroidManifest.xml文件中的application标签下添加:

android:name="org.litepal.LitePalApplication"

2、创建数据库

LitePal采取了对象关系映射模型(ORM)的模式,即建立面向对象语言和关系型数据库之间的一种映射关系,使用面向对象的思维来操作数据库。

(1)将数据库的表看做一个类,采用JavaBean的方式定义这个类(模型类),如:

public class Book {

    private int id;

    private String author;

    private double price;

    private int pages;

    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(2)将Book类添加到映射模型列表中。修改litepal.xml中的代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<litepal>
    <dbname value="BookStore" ></dbname>

    <version value="1" ></version>

    <list>
        <mapping class="com.songzheng.litepaltest.Book"></mapping>
    </list>
</litepal>

这里使用mapping标签声明要配置的映射模型类,注意一定要使用完整的类名。不管有多少模型(表)需要映射,都使用同样的方式配置在list标签下即可。

(3)修改MainActivity中的代码:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    btCreateDatabase = (Button) findViewById(R.id.bt_create_database);
    btCreateDatabase.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Connector.getDatabase();
        }
    });
}

其中Connector是org.litepal.tablemanager中的一个类。执行Connector的getDatabase()方法即可创建数据库。

3、升级数据库

如果想要向已有的表中添加字段,可直接向对应的模型类添加相应字段及其Getter和Setter方法;如果想要新增一张表,只需新建一个对应的模型类,并添加到litepal.xml中的映射模型列表。修改完成后记得将litepal.xml文件中的版本号加1,然后重新执行Connector的getDatabase()方法即可。

升级数据库是LitePal还会保留之前表中的所有数据,这样就不会造成数据丢失了。

4、使用LitePal添加数据

使用LitePal添加数据,只需创建出模型类的实例,再将要存储的数据设置好,最后调用一下模型类的save()方法即可。但进行CRUD操作时要使模型类继承自DataSupport类。

btAddData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Book book = new Book();
        book.setName("The Da Vinci Code");
        book.setAuthor("Dan Brown");
        book.setPages(454);
        book.setPrice(16.69);
        book.setPress("Unknown");
        book.save();    //save()方法继承自DataSupport类
    }
});

5、使用LitePal更新数据

(1)对已经存储的对象重新设值,然后重新调用save()方法。

btUpdateData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Book book = new Book();
        book.setName("The Lost Symbol");
        book.setAuthor("Dan Brown");
        book.setPages(510);
        book.setPrice(19.95);
        book.setPress("Unknown");
        book.save();
        book.setPrice(10.99);
        book.save();
    }
});

已存储对象:对于LitePal,对象是否已经存储是通过model.isSaved()方法判断的,返回true表示已存储,false表示未存储。只有两种情况下model.isSaved()会返回true,一种是已经调用过该model的save()方法了,另一种是通过LitePal提供的查询API查出来的,由于是数据库中查到的对象,所以会被认为是已存储的对象。

(2)使用模型类的updateAll()方法。首先创建一个模型对象,设置要更新的数据,然后调用该模型对象的updateAll()方法,其中可使用类似于SQLiteDatabase的条件语句控制要更新的行,如果不指定条件语句,就表示更新所有数据。

btUpdateData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Book book = new Book();
        book.setPrice(14.95);
        book.setPress("Anchor");
        book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan Brown");
    }
});

不过,在使用updateAll()方法时,想把一个字段的值更新成默认值,就不能使用set方法,如int类型的默认值是0,通过set修改该int型为0,然后再使用updateAll()方法修改数据库中对应的int值为0,这是不可行的,例如:把数据库表中的pages列更新为0,直接调用book.setPages(0)是不可行的,LitePal不会对默认值的字段进行更新,想将数据更新成默认值,可以使用模型类的setToDefault()方法,传入相应的列名即可。如:

Book book = new Book();
book.setToDefault("pages");
book.updateAll();   //这样使用会将所有pages字段设置为默认值0。也可以通过使用约束条件只使某一行的的pages字段为默认值

6、使用LitePal删除数据

(1)调用已存储对象的delete()方法。

(2)调用DataSupport类的deleteAll()方法。其中第一个参数指定删除哪张表中的数据,如Book.class表示删除Book表中的数据,后面的参数用于指定约束条件。

btDeleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        DataSupport.deleteAll(Book.class, "price < ?", "15");
    }
});

7、使用LitePal查询数据

调用DataSupport的findXxx()方法进行查询操作。如:

List<Book> books = DataSupport.findAll(Book.class); //查询Book表中所有的数据

MainActivity.java:

btQueryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        List<Book> books = DataSupport.findAll(Book.class);
        for (Book book : books) {
            Log.d("MainActivity", "book name is " + book.getName());
            Log.d("MainActivity", "book author is " + book.getAuthor());
            Log.d("MainActivity", "book pages is " + book.getPages());
            Log.d("MainActivity", "book price is " + book.getPrice());
            Log.d("MainActivity", "book press is " + book.getPress());
        }
    }
});

除了findAll()方法之外,LitePal还提供了很多查询API,如:

Book firstBook = DataSupport.findFirst(Book.class);     //查询Book表中的第一条数据
Book lastBook = DataSupport.findLast(Book.class);       //查询Book表中的最后一条数据

还可以使用连缀查询来定制更多的查询功能。如:

  • select()方法用于指定查询哪几列的数据,对应SQL当中的select关键字。比如只查询name和author两列数据:

    List<Book> books = DataSupport.select("name", "author").find(Book.class);
    
  • where()方法用于指定查询的约束条件,对应了SQL当中的where关键字。比如只查询页数大于400的数据:

    List<Book> books = DataSupport.where("pages > ?", "400").find(Book.class);
    
  • order()方法用于指定结果的排序方式,对应了SQL当中的order by关键字。比如将查询结果按价格从高到低排序:

    List<Book> books = DataSupport.order("price desc").find(Book.class);    //desc表示降序,asc或者不写表示升序
    
  • limit()方法用于指定查询结果的数量。比如只查询表中前3条数据:

    List<Book> books = DataSupport.limit(3).find(Book.class);
    
  • offset()方法用于指定查询结果的偏移量,比如查询表中的第2条、第3条、第4条数据:

    List<Book> books = DataSupport.limit(3).offset(1).find(Book.class);
    
  • 最后还可以对这5个方法进行任意的连缀组合查询,如:

    List<Book> books = DataSupport.select("name", "author", "pages")
                                  .where("pages > ?", "400")
                                  .order("pages")   //按页数升序排列
                                  .limit(10)
                                  .offset(10).find(Book.class);
    
  • LitePal还支持原生的SQL来进行查询:

    Cursor cursor = DataSupport.findBySQL("select * from Book where pages > ? and price < ?", "400", "20");
    

    然后从获取的Cursor对象中读取数据。

猜你喜欢

转载自blog.csdn.net/qq_32651225/article/details/55670794