• 数据存储-持久化技术


    使用文件存储数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public void save(String inputText){

    FileOutputStream out = null;
    BufferedWriter writer = null;

    try {
    out = openFileOutput("data",Context.MODE_PRIVATE);
    writer = new BufferedWriter(new OutputStreamWriter(out));
    writer.write(inputText);
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    if(writer != null){
    writer.close();
    }
    } catch (IOException e){
    e.printStackTrace();
    }
    }
    }

    使用openFileOutput/openFileInput搭配相应的java输入输出流使用文件来存储数据。另外,记得writer.close()。

    读取文件就将FileOutputStream->FileInputStreamBufferedWriter->BufferedReader,wirter.write->reader.redline()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public String load(){

    FileInputStream inputStream = null;
    BufferedReader reader = null;
    StringBuilder content = new StringBuilder();

    try {
    inputStream = openFileInput("data");
    reader = new BufferedReader(new InputStreamReader(inputStream));
    String line = "";
    while ((line = reader.readLine()) != null){
    content.append(line);
    }
    } catch (IOException e){
    e.printStackTrace();
    } finally {
    if (reader != null){
    try {
    reader.close();
    } catch (IOException e){
    e.printStackTrace();
    }
    }
    }
    return content.toString();
    }

    使用SharedPreferences存储数据

    存放数据

    1
    2
    3
    4
    5
    SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
    editor.putString("name","Gaby");
    editor.putBoolean("married",false);
    editor.putInt("age",19);
    editor.commit();

    数据以xml的形式存在

    取数据

    1
    2
    3
    4
    5
    6
    7
    SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);//输入相对应的文件名
    String name = pref.getString("name", "");
    int age = pref.getInt("age",29);
    Boolean married = pref.getBoolean("married",false);
    Log.d("MainActivity","name is" + name);
    Log.d("MainActivity","age is" + age);
    Log.d("MainActivity","married is " + married);

    加深理解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SharedPreferences pref;
    SharedPreferences.Editor editor;

    pref = PreferenceManager.getDefaultSharedPreferences(this);

    editor = pref.edit();

    editor.putBoolean("remember_password", true); editor.putString("account", account);
    editor.putString("password", password);
    editor.commit();

    editor.clear();//将SharedPreference中的数据全部清除掉t

    使用SQLite(DBMS)创建数据库存储数据

    细节理解:

    1
    2
    3
    dbHelper = new MyDatabaseHelpoer(MainActivity.this,"BookStore.db",null,1);//构建一个MydatabaseHelper对象

    dbHelper.getWritableDatabase();//没找到BookStore.db这个数据库,即调用onCreate()创建该数据库

    创建MyDatabaseHelper继承自SQLiteOpenHelper,覆写onCreate(),onCreate()中只需要包含数据库的操作就可以了(该数据库的名字即为构造函数中传入的名字)

    一个MyDatabaseHelper的对象创建一个数据库,在onCreate()函数中执行对这个数据库的操作

    创建好后,用ddms的explorer(顶上Tools->Android->Android Device Monitor->File Exploer,FileExplorer里的文件目录即为模拟器的文件目录)不能看到改数据库创建的表,用adb shell(adb是一个对连接的usb设备或者模拟器的调试器)看。要使用adb,需要先配置环境变量:增加C:UsersGabyAppDataLocalAndroidsdkplatform-tools到系统变量里面的Path,就可以在android studio 的terminal里使用

    FileExplorer中/data/data/com.example.gaby.databasetest/databases/目录下有两个文件

    • xxx.db数据库
    • xxx.db-journal是为让数据库能够支持事务而产生的临时日志文件

    建表语句:

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

    adb命令列举:

    adb devices 列出当前设备
    adb shell 进入设备的控制台
    cd /data/data/com.example.gaby.databasetest/databases/进入模拟器该文件夹下
    ls列出该目录下文件夹
    sqlite3 BookStore.db 打开数据库

    SQLite命令:

    .table显示数据库中有哪些表
    .schema查看建表语句
    .exit/.quit 退出改数据库
    select * from tableName;(有分号) 查询该表下有哪些纪录
    接着exit退出设备控制台(adb)

    注意execSQL(String s)传入的是字符串

    CRUD

    以下是按Android提供过的API来做的,实际上还可直接用SQL来操作数据库,见《第一行代码》page 260

    向数据库中添加数据(db.insert()) (·)Create 添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    addData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    ContentValues values = new ContentValues();
    //di yi zu
    values.put("name", "Game Of Thrones");
    values.put("price",70.29);
    values.put("author","George Martin");
    values.put("pages",800);
    db.insert("Book", null, values);
    //di er zu
    values.clear();
    values.put("name","KaiFu's Saying");
    values.put("price",50.34);
    values.put("author","KaiFu");
    values.put("pages",300);
    db.insert("Book", null, values);
    }
    });

    getWritableDatabase()和getReadableDatabase()除了升级和创建数据库,该方法本身会返回SQLiteDatabase对象。db.insert(“表名”, null, ContentValue对象)。

    查询数据(db.query()) (·)Retrieve
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    queryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    Cursor cursor = db.query("Book",null,null,null,null,null,null);
    if(cursor.moveToFirst()){
    do{
    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());
    }

    }
    });

    db.query()返回Cursor对象

    更新数据(db.update()) (·)Update 更新

    注意:在MyDatabaseHelper中的onUpgrade()方法是用于升级数据库(如 多建/删除 一张表)。而更新数据,则是在特定表上修改数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    updataData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put("price",12.33);
    db.update("Book", values, "name = ?",new String [] {"Game Of Thrones"});
    }
    });
    删除数据(db.delete) (·)Delete 删除
    1
    2
    3
    4
    5
    6
    7
    deleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.delete("Book","pages > ?", new String[] { "300" });
    }
    });

    删除Book表中pages列值大于300的记录

    数据库的事务(ACID要么全成功,要么全失败)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    replaceData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.beginTransaction();
    try {
    db.delete("Book",null,null);

    ContentValues values = new ContentValues();
    values.put("name","MySQL Crash Course");
    values.put("price",12.93);
    values.put("pages",400);
    values.put("author","Ben Forta");
    db.insert("Book",null,values);
    db.setTransactionSuccessful();
    } catch (Exception e){
    e.printStackTrace();
    } finally {
    db.endTransaction();
    }

    }
    });

    解读:中途出现异常,db.setTransactionSuccessful()得不到执行,当结束事务db.endTransaction()时发现事务未成功执行,旧数据就不会被删除

    升级数据库的最佳写法

    需要注意以下几点:

    • 当用户下载的新版本覆盖安装旧版本时,实际上安装好的新版本应用程序具备所有新功能,只是数据库还残留在上一个版本,此时如果代码如下:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      private MyDatabaseHelpoer dbHelper;
      dbHelper = new MyDatabaseHelpoer(MainActivity.this,"BookStore.db",null,6);
      Button createDatabase = (Button) findViewById(R.id.createDatebase);
      createDatabase.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
      dbHelper.getWritableDatabase();
      }
      });

    则可视为手动更新数据库。如果将

    1
    2
    3
    private MyDatabaseHelpoer dbHelper;
    dbHelper = new MyDatabaseHelpoer(MainActivity.this,"BookStore.db",null,6);
    dbHelper.getWritableDatabase();

    直接放置在主活动的onCreate(),而不放置在某个监听中,那么伴随活动的启动,数据库就被更新了。需要注意的是,dbHelper.getWritableDatabase()是在没有名为”BookStore.db”的数据库时就创建(执行MydatabaseHelperonCreate()函数)。如果本来就有,就会去执行onUpdate()函数,判断旧版本是哪一个,进而做出对数据库的更改

    • 新版本的不光要在onUpgrade()做出更改,还应以备旧版本更新。更要在onCreate()中做出完整的创建工作,以备用户直接下载新版本

    • onUpgrade() 中的 case 不加 break , 原因就是如果跨版本升级。比如旧版本的数据库停留在第二版,应用安装好了,且新版本的数据库是第8版,在更新数据库时就要从第二版更新到第八版,依次升级,升级结束后此时的数据库版本号为8

      1
      2
      3
      4
      5
      6
      7
      8
      9
      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      switch (oldVersion){
      case 4:
      db.execSQL(CREATE_MILK);

      case 5:
      db.execSQL("alter table Milk add column volume real");
      }
      }

    个人想法

    对于版本更新的问题,比如手机版的qq,不可能没更新一个版本就在,onUpgrade()里加一个型号,应该会要有个版本间隔(允许的最新和最旧的版本区间),不然200年以后,以腾讯的产品迭代速度,onUpgrade()里面的代码就太多了…

  • 相关阅读:
    Django(28)Django模板介绍
    Django(27)Django类视图添加装饰器
    HTTP协议-返回结果的HTTP状态
    HTTP协议二
    HTTP协议 一
    HTTP 协议用于客户端和服务器端之间 的通信
    Net分布式系统之一:系统整体框架介绍
    数据结构-实现正负数重新排序
    数据结构-合并两个已经排序的数组
    数据结构-查找第一个没有重复的数组元素
  • 原文地址:https://www.cnblogs.com/gabygoole/p/5299883.html
Copyright © 2020-2023  润新知