Android学习之路之数据存储(二)

目录

  • 写在前面
  • [2. 共享参数:SharedPreferences](#2. 共享参数:SharedPreferences)
    • [2.1 SharedPreferences常用操作](#2.1 SharedPreferences常用操作)
      • [2.1.1 写操作](#2.1.1 写操作)
      • [2.1.2 读操作](#2.1.2 读操作)
  • [3. 数据库:SQLite](#3. 数据库:SQLite)
    • [3.1 SQLite的基本用法](#3.1 SQLite的基本用法)
      • [3.1.1 SQLiteDatabase相关API](#3.1.1 SQLiteDatabase相关API)
    • [3.2 数据库帮助器SQLiteOpenHelper](#3.2 数据库帮助器SQLiteOpenHelper)
      • [3.2.1 相关实例](#3.2.1 相关实例)

写在前面

Android有五种主要存储方式的用法,包括

  1. SD卡文件
  2. 共享参数:SharedPreferences
  3. 数据库:SQLite
  4. 应用Application基础
  5. 内容提供器:ContentProvider

下面,我们将要讲解一下共享参数:SharedPreferences和数据库:SQLite


2. 共享参数:SharedPreferences

SharedPreferences是Android的一个轻量级存储工具,SharedPreferences的存储介质是符合XML规范的配置文件。保存SharedPreferences键值对信息的文件路径是/data/data/应用包名/shared_prefs/文件名.xml

xml 复制代码
<?xml version='1.0 encoding='utf-8' standalone='yes'?>
<map>
	<string name="name">Xiao ming</string>
	<int name="age" value="30"/>
	<boolean name="married" value="true"/>
	<float name="weight" value="100.0"/>
</map>

SharedPreferences主要适用于如下场合:

  1. 简单且孤立的数据。
  2. 文本形式的数据。
  3. 需要持久化存储的数据。在App退出后再次启动时,之前保存的数据仍然有效。

2.1 SharedPreferences常用操作

java 复制代码
// 从share.xml中获取共享参数对象
// 第一个参数是文件名,上面的share表示当前使用的共享参数文件名是share.xml
// 第二个参数是操作模式,一般都填 MODE_PRIVATE,表示私有模式
SharedPreferences shared = getSharedPreferences("share", MODE_PRIVATE);

2.1.1 写操作

java 复制代码
SharedPreferences.Editor editor = shared.edit(); // 获得编辑器的对象
editor.putString("name", "Mr Lee"); // 添加一个名叫name的字符串参数
editor.putInt("age", 30); // 添加一个名叫age的整型参数
editor.putBoolean("married", true); // 添加一个名叫married的布尔型参数
editor.putFloat("weight", 100f); // 添加一个名叫weight的浮点数参数
editor.commit(); // 提交编辑器中的修改

2.1.2 读操作

java 复制代码
String name = shared.getString("name", ""); // 从共享参数中获得名叫name的字符串
int age = shared.getInt("age", 0); // 从共享参数中获得名叫age的整型数
boolean married = shared.getBoolean("married", false); // 从共享参数中获得名叫married的布尔数
float weight = shared.getFloat("weight", 0); // 从共享参数中获得名叫weight的浮点数

3. 数据库:SQLite

3.1 SQLite的基本用法

SQLiteDatabase是SQLite的数据库管理类,开发者可以在活动页面代码或任何能取到Context的地方获取

java 复制代码
/ 创建名叫test.db的数据库。数据库如果不存在就创建它,如果存在就打开它
 SQLiteDatabase db = openOrCreateDatabase(mDatabaseName, Context.MODE_PRIVATE, null);
// 删除名叫test.db数据库
// deleteDatabase(getFilesDir()+"/test.db");

3.1.1 SQLiteDatabase相关API

SQLiteDatabase提供了若干操作数据表的API,常用的方法有3类

  1. 管理类,用于数据库层面的操作

    • openDatabase:打开指定路径的数据库
    • isOpen:判断数据库是否已打开
    • close:关闭数据库
    • getVersion:获取数据库的版本号
    • setVersion:设置数据库的版本号
  2. 事务类,用于事务层面的操作

    • beginTransaction:开始事务
    • setTransactionSuccessful:设置事务的成功标志。
    • endTransaction:结束事务。执行本方法时,系统会判断是否已执行setTransactionSuccessful,如果之前已设置就提交,如果没有设置就回滚
  3. 数据处理类,用于数据表层面的操作

    • execSQL:执行拼接好的SQL控制语句。一般用于建表、删表、变更表结构。
    • delete:删除符合条件的记录
    • update:更新符合条件的记录
    • insert:插入一条记录
    • query:执行查询操作,返回结果集的游标
    • rawQuery:执行拼接好的SQL查询语句,返回结果集的游标

3.2 数据库帮助器SQLiteOpenHelper

SQLiteDatabase存在局限性,例如必须小心、不能重复地打开数据库,处理数据库的升级很不方便。

Android提供了一个辅助工具: SQLiteOpenHelper,用于指导开发者进行SQLite的合理使用。

SQLiteOpenHelper的具体使用步骤

  • 新建一个继承自SQLiteOpenHelper的数据库操作类,重写onCreate和onUpgrade两个方法。

    • onCreate方法只在第一次打开数据库时执行,在此可进行表结构创建的操作;
    • onUpgrade方法在数据库版本升高时执行,因此可以在onUpgrade函数内部根据新旧版本号进行表结构变更处理。
  • 封装保证数据库安全的必要方法,包括:

    • 获取单例对象
    • 打开数据库连接
    • 关闭数据库连接
  • 提供对表记录进行增加、删除、修改、查询的操作方法

    • SQLite可直接使用的数据结构是ContentValues类,类似于映射Map,提供put和get方法用来存取键值对。

3.2.1 相关实例

  • UserDBHelper 类
java 复制代码
package com.example.storage.database;

import java.util.ArrayList;

import com.example.storage.bean.UserInfo;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

@SuppressLint("DefaultLocale")
public class UserDBHelper extends SQLiteOpenHelper {
    private static final String TAG = "UserDBHelper";
    private static final String DB_NAME = "user.db"; // 数据库的名称
    private static final int DB_VERSION = 1; // 数据库的版本号
    private static UserDBHelper mHelper = null; // 数据库帮助器的实例
    private SQLiteDatabase mDB = null; // 数据库的实例
    public static final String TABLE_NAME = "user_info"; // 表的名称

    private UserDBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    private UserDBHelper(Context context, int version) {
        super(context, DB_NAME, null, version);
    }

    // 利用单例模式获取数据库帮助器的唯一实例
    public static UserDBHelper getInstance(Context context, int version) {
        if (version > 0 && mHelper == null) {
            mHelper = new UserDBHelper(context, version);
        } else if (mHelper == null) {
            mHelper = new UserDBHelper(context);
        }
        return mHelper;
    }

    // 打开数据库的读连接
    public SQLiteDatabase openReadLink() {
        if (mDB == null || !mDB.isOpen()) {
            mDB = mHelper.getReadableDatabase();
        }
        return mDB;
    }

    // 打开数据库的写连接
    public SQLiteDatabase openWriteLink() {
        if (mDB == null || !mDB.isOpen()) {
            mDB = mHelper.getWritableDatabase();
        }
        return mDB;
    }

    // 关闭数据库连接
    public void closeLink() {
        if (mDB != null && mDB.isOpen()) {
            mDB.close();
            mDB = null;
        }
    }

    // 创建数据库,执行建表语句
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "onCreate");
        String drop_sql = "DROP TABLE IF EXISTS " + TABLE_NAME + ";";
        Log.d(TAG, "drop_sql:" + drop_sql);
        db.execSQL(drop_sql);
        String create_sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
                + "_id INTEGER PRIMARY KEY  AUTOINCREMENT NOT NULL,"
                + "name VARCHAR NOT NULL," + "age INTEGER NOT NULL,"
                + "height LONG NOT NULL," + "weight FLOAT NOT NULL,"
                + "married INTEGER NOT NULL," + "update_time VARCHAR NOT NULL"
                //演示数据库升级时要先把下面这行注释
                + ",phone VARCHAR" + ",password VARCHAR"
                + ");";
        Log.d(TAG, "create_sql:" + create_sql);
        db.execSQL(create_sql);
    }

    // 修改数据库,执行表结构变更语句
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG, "onUpgrade oldVersion=" + oldVersion + ", newVersion=" + newVersion);
        if (newVersion > 1) {
            //Android的ALTER命令不支持一次添加多列,只能分多次添加
            String alter_sql = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + "phone VARCHAR;";
            Log.d(TAG, "alter_sql:" + alter_sql);
            db.execSQL(alter_sql);
            alter_sql = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + "password VARCHAR;";
            Log.d(TAG, "alter_sql:" + alter_sql);
            db.execSQL(alter_sql);
        }
    }

    // 根据指定条件删除表记录
    public int delete(String condition) {
        // 执行删除记录动作,该语句返回删除记录的数目
        return mDB.delete(TABLE_NAME, condition, null);
    }

    // 删除该表的所有记录
    public int deleteAll() {
        // 执行删除记录动作,该语句返回删除记录的数目
        return mDB.delete(TABLE_NAME, "1=1", null);
    }

    // 往该表添加一条记录
    public long insert(UserInfo info) {
        ArrayList<UserInfo> infoArray = new ArrayList<UserInfo>();
        infoArray.add(info);
        return insert(infoArray);
    }

    // 往该表添加多条记录
    public long insert(ArrayList<UserInfo> infoArray) {
        long result = -1;
        for (int i = 0; i < infoArray.size(); i++) {
            UserInfo info = infoArray.get(i);
            ArrayList<UserInfo> tempArray = new ArrayList<UserInfo>();
            // 如果存在同名记录,则更新记录
            // 注意条件语句的等号后面要用单引号括起来
            if (info.name != null && info.name.length() > 0) {
                String condition = String.format("name='%s'", info.name);
                tempArray = query(condition);
                if (tempArray.size() > 0) {
                    update(info, condition);
                    result = tempArray.get(0).rowid;
                    continue;
                }
            }
            // 如果存在同样的手机号码,则更新记录
            if (info.phone != null && info.phone.length() > 0) {
                String condition = String.format("phone='%s'", info.phone);
                tempArray = query(condition);
                if (tempArray.size() > 0) {
                    update(info, condition);
                    result = tempArray.get(0).rowid;
                    continue;
                }
            }
            // 不存在唯一性重复的记录,则插入新记录
            ContentValues cv = new ContentValues();
            cv.put("name", info.name);
            cv.put("age", info.age);
            cv.put("height", info.height);
            cv.put("weight", info.weight);
            cv.put("married", info.married);
            cv.put("update_time", info.update_time);
            cv.put("phone", info.phone);
            cv.put("password", info.password);
            // 执行插入记录动作,该语句返回插入记录的行号
            result = mDB.insert(TABLE_NAME, "", cv);
            // 添加成功后返回行号,失败后返回-1
            if (result == -1) {
                return result;
            }
        }
        return result;
    }

    // 根据条件更新指定的表记录
    public int update(UserInfo info, String condition) {
        ContentValues cv = new ContentValues();
        cv.put("name", info.name);
        cv.put("age", info.age);
        cv.put("height", info.height);
        cv.put("weight", info.weight);
        cv.put("married", info.married);
        cv.put("update_time", info.update_time);
        cv.put("phone", info.phone);
        cv.put("password", info.password);
        // 执行更新记录动作,该语句返回记录更新的数目
        return mDB.update(TABLE_NAME, cv, condition, null);
    }

    public int update(UserInfo info) {
        // 执行更新记录动作,该语句返回记录更新的数目
        return update(info, "rowid=" + info.rowid);
    }

    // 根据指定条件查询记录,并返回结果数据队列
    public ArrayList<UserInfo> query(String condition) {
        String sql = String.format("select rowid,_id,name,age,height,weight,married,update_time," +
                "phone,password from %s where %s;", TABLE_NAME, condition);
        Log.d(TAG, "query sql: " + sql);
        ArrayList<UserInfo> infoArray = new ArrayList<UserInfo>();
        // 执行记录查询动作,该语句返回结果集的游标
        Cursor cursor = mDB.rawQuery(sql, null);
        // 循环取出游标指向的每条记录
        while (cursor.moveToNext()) {
            UserInfo info = new UserInfo();
            info.rowid = cursor.getLong(0); // 取出长整型数
            info.xuhao = cursor.getInt(1); // 取出整型数
            info.name = cursor.getString(2); // 取出字符串
            info.age = cursor.getInt(3);
            info.height = cursor.getLong(4);
            info.weight = cursor.getFloat(5); // 取出浮点数
            //SQLite没有布尔型,用0表示false,用1表示true
            info.married = (cursor.getInt(6) == 0) ? false : true;
            info.update_time = cursor.getString(7);
            info.phone = cursor.getString(8);
            info.password = cursor.getString(9);
            infoArray.add(info);
        }
        cursor.close(); // 查询完毕,关闭游标
        return infoArray;
    }

    // 根据手机号码查询指定记录
    public UserInfo queryByPhone(String phone) {
        UserInfo info = null;
        ArrayList<UserInfo> infoArray = query(String.format("phone='%s'", phone));
        if (infoArray.size() > 0) {
            info = infoArray.get(0);
        }
        return info;
    }

}
  • SQLite读操作:SQLiteReadActivity
java 复制代码
package com.example.storage;

import java.util.ArrayList;

import com.example.storage.bean.UserInfo;
import com.example.storage.database.UserDBHelper;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;

@SuppressLint("DefaultLocale")
public class SQLiteReadActivity extends AppCompatActivity implements OnClickListener {
    private UserDBHelper mHelper; // 声明一个用户数据库帮助器的对象
    private TextView tv_sqlite;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite_read);
        tv_sqlite = findViewById(R.id.tv_sqlite);
        findViewById(R.id.btn_delete).setOnClickListener(this);
    }

    // 读取数据库中保存的所有用户记录
    private void readSQLite() {
        if (mHelper == null) {
            showToast("数据库连接为空");
            return;
        }
        // 执行数据库帮助器的查询操作
        ArrayList<UserInfo> userArray = mHelper.query("1=1");
        String desc = String.format("数据库查询到%d条记录,详情如下:", userArray.size());
        for (int i = 0; i < userArray.size(); i++) {
            UserInfo info = userArray.get(i);
            desc = String.format("%s\n第%d条记录信息如下:", desc, i + 1);
            desc = String.format("%s\n 姓名为%s", desc, info.name);
            desc = String.format("%s\n 年龄为%d", desc, info.age);
            desc = String.format("%s\n 身高为%d", desc, info.height);
            desc = String.format("%s\n 体重为%f", desc, info.weight);
            desc = String.format("%s\n 婚否为%b", desc, info.married);
            desc = String.format("%s\n 更新时间为%s", desc, info.update_time);
        }
        if (userArray.size() <= 0) {
            desc = "数据库查询到的记录为空";
        }
        tv_sqlite.setText(desc);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 获得数据库帮助器的实例
        mHelper = UserDBHelper.getInstance(this, 2);
        // 打开数据库帮助器的读连接
        mHelper.openReadLink();
        readSQLite();
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 关闭数据库连接
        mHelper.closeLink();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_delete) {
            // 关闭数据库连接
            mHelper.closeLink();
            // 打开数据库帮助器的写连接
            mHelper.openWriteLink();
            // 删除所有记录
            mHelper.deleteAll();
            // 关闭数据库连接
            mHelper.closeLink();
            // 打开数据库帮助器的读连接
            mHelper.openReadLink();
            readSQLite();
        }
    }

    private void showToast(String desc) {
        Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
    }

}
  • SQLite写操作:SQLiteWriteActivity
java 复制代码
package com.example.storage;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

import com.example.storage.bean.UserInfo;
import com.example.storage.database.UserDBHelper;
import com.example.storage.util.DateUtil;

public class SQLiteWriteActivity extends AppCompatActivity implements OnClickListener {
    private UserDBHelper mHelper; // 声明一个用户数据库帮助器的对象
    private EditText et_name;
    private EditText et_age;
    private EditText et_height;
    private EditText et_weight;
    private boolean bMarried = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite_write);
        et_name = findViewById(R.id.et_name);
        et_age = findViewById(R.id.et_age);
        et_height = findViewById(R.id.et_height);
        et_weight = findViewById(R.id.et_weight);
        findViewById(R.id.btn_save).setOnClickListener(this);
        initTypeSpinner();
    }

    // 初始化婚姻状况的下拉框
    private void initTypeSpinner() {
        ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>(this,
                R.layout.item_select, typeArray);
        typeAdapter.setDropDownViewResource(R.layout.item_dropdown);
        Spinner sp_married = findViewById(R.id.sp_married);
        sp_married.setPrompt("请选择婚姻状况");
        sp_married.setAdapter(typeAdapter);
        sp_married.setSelection(0);
        sp_married.setOnItemSelectedListener(new TypeSelectedListener());
    }

    private String[] typeArray = {"未婚", "已婚"};
    class TypeSelectedListener implements OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            bMarried = (arg2 == 0) ? false : true;
        }

        public void onNothingSelected(AdapterView<?> arg0) {
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 获得数据库帮助器的实例
        mHelper = UserDBHelper.getInstance(this, 2);
        // 打开数据库帮助器的写连接
        mHelper.openWriteLink();
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 关闭数据库连接
        mHelper.closeLink();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_save) {
            String name = et_name.getText().toString();
            String age = et_age.getText().toString();
            String height = et_height.getText().toString();
            String weight = et_weight.getText().toString();
            if (TextUtils.isEmpty(name)) {
                showToast("请先填写姓名");
                return;
            } else if (TextUtils.isEmpty(age)) {
                showToast("请先填写年龄");
                return;
            } else if (TextUtils.isEmpty(height)) {
                showToast("请先填写身高");
                return;
            } else if (TextUtils.isEmpty(weight)) {
                showToast("请先填写体重");
                return;
            }
            // 以下声明一个用户信息对象,并填写它的各字段值
            UserInfo info = new UserInfo();
            info.name = name;
            info.age = Integer.parseInt(age);
            info.height = Long.parseLong(height);
            info.weight = Float.parseFloat(weight);
            info.married = bMarried;
            info.update_time = DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss");
            // 执行数据库帮助器的插入操作
            mHelper.insert(info);
            showToast("数据已写入SQLite数据库");
        }
    }

    private void showToast(String desc) {
        Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
    }

}
相关推荐
Meteors.40 分钟前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton1 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
冒泡的肥皂2 小时前
MVCC初学demo(一
数据库·后端·mysql
.Shu.3 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
whysqwhw5 小时前
安卓图片性能优化技巧
android
薛晓刚6 小时前
当MySQL的int不够用了
数据库
风往哪边走6 小时前
自定义底部筛选弹框
android
SelectDB技术团队6 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光6 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12016 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql