Android数据持久化

1.内部存储1:

1)SharedPreferences :共享参数,使用简单,使用xml格式存储,一般用来存储系统设置。
目录:data/data/{包名}/shared_prefs

//使用共享参数保存数据    public void saveData(View v)    {        //获取共享参数对象        //第一个参数是共享参数文件的名字        //第二个参数是对该文件的操作模式        SharedPreferences shared = getSharedPreferences("configration",Context.MODE_PRIVATE);               //获取共享参数编辑对象        SharedPreferences.Editor edit = shared.edit();              //使用编辑对象存储数据        edit.putFloat("fontSize", fontSize);        edit.putInt("fontColor", fontColor);        edit.putInt("backColor", backColor);                //提交        edit.commit();    }//使用共享参数读取数据public void readData(View v)    {        //获取共享参数对象        //第一个参数是被读取的共享参数文件        SharedPreferences shared = getSharedPreferences("configration", Context.MODE_PRIVATE);        fontSize = shared.getFloat("fontSize", 25);        fontColor = shared.getInt("fontColor", Color.GRAY);        backColor = shared.getInt("backColor", Color.WHITE);        textView.setTextSize(fontSize);        textView.setTextColor(fontColor);        textView.setBackgroundColor(backColor);         }

2)内部存储2:

内部存储的文件的存放位置 /data/data/(包名)/files/
系统封装好了openFileOutput(filename, Context.MODE_PRIVATE)方法和openFileInput(filename)方法。

//把数据保存到内部存储空间的文件中public void saveFile(View v) throws IOException{        //获取文件名和文件内容        String filename = edit_fileName.getText().toString().trim();        String filecontent = edit_content.getText().toString().trim();              FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE);        fos.write(filecontent.getBytes());        fos.close();    }    public void readData(View v) throws IOException{        //获取被读取的文件名        String filename = edit_fileName.getText().toString().trim();        //读取文件        FileInputStream fis = openFileInput(filename);        byte[] arr = new byte[fis.available()];        int len = fis.read(arr);        edit_content.setText(new String(arr,0,len));        fis.close();    }

2.外部存储

文件操作工具类:

/** * * 扩展卡种文件操作的工具类: 以缓存图片为例: 目录:mnt/sdcard */public class FileUtil {    // 存储图片的目录    // Environment.getExternalStorageDirectory() :获取外部存储空间的目录    public static final String IMAGE_URL = Environment            .getExternalStorageDirectory() + "/by/images";    public static final int FORMAT_PNG = 1;    public static final int FORMAT_JPEG = 2;    /** * 判断扩展卡是否挂载 * @return */    public static boolean isMounted() {        String state = Environment.getExternalStorageState();        return state.equals(Environment.MEDIA_MOUNTED);    }    /** * 判断扩展卡的剩余空间够不够用 */    public static boolean  isAble()    {        //文件系统状态管理对象StatFs fs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());        int count = fs.getFreeBlocks();//空闲的数据块个数        int size =  fs.getBlockSize();//返回每个数据块的大小         //剩余空间大小        long  total = count*size;//单位是字节        int  t = (int) (total/1024/1024);        if(t>2)            return true;        else            return false;    }    /** * 保存图片到扩展卡的功能 * @throws IOException */    public static void saveImage(String url, byte[] data) throws IOException { // 判断扩展卡是否挂载        if (!isMounted())            return;        // 判断存储目录是否存在        File dir = new File(IMAGE_URL);        if (!dir.exists())            dir.mkdirs();        // 把图片数据写入到一个图片文件        FileOutputStream fos = new FileOutputStream(new File(dir,                getFileName(url)));        fos.write(data);        fos.close();    }    /** * 保存图片到扩展卡的功能 * @throws FileNotFoundException */    public static void saveImage(String url, Bitmap bitmap, int format)            throws FileNotFoundException {        // 判断扩展卡是否挂载        if (!isMounted())            return;        // 判断存储目录是否存在        File dir = new File(IMAGE_URL);        if (!dir.exists())            dir.mkdirs();        // 把图片数据写入到一个图片文件        FileOutputStream fos = new FileOutputStream(new File(dir,                getFileName(url)));        // 图片的压缩 CompressFormat.PNG:压缩之后的格式        bitmap.compress(format == 1 ? CompressFormat.PNG : CompressFormat.JPEG,                100, fos);    }    /** * 从扩展卡读取图片的功能 */    public static Bitmap readImage(String url) {        // 判断扩展卡是否挂载        if (!isMounted())            return null;        String filename = getFileName(url);        File file = new File(IMAGE_URL, filename);        Bitmap bitmap = null;        if(file.exists())            bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());        return bitmap;    }    /** * 清空扩展卡 缓存目录中的内容的功能 */    public static void clear() {        // 判断扩展卡是否挂载        if (!isMounted())            return;        File dir = new File(IMAGE_URL);        if (dir.exists()) {              File[] arr = dir.listFiles();              for(File f:arr)              {                  f.delete();              }        }    }    /** * 根据文件的下载路径获取文件名 * @param url * @return */    public static String getFileName(String url) {        return url.substring(url.lastIndexOf("/") + 1);    }}

3.数据库存储

**3.1从外部导入的数据库操作**

a)从外部把数据库文件push到扩展卡中,通过数据库文件路径得到数据库
b)在程序内部创建数据库
c)游标中的数据变化时,数据源用cursor时,要调用adapter(SimpleCursorAdapter)的swapCursor方法通知数据变化,

    public void loadData()//加载数据    {        SQLiteDatabase db = dbHelper.getReadableDatabase();        cursor = db.query("t_user", columns, null, null, null, null, null);             //游标中的数据变化了,需要切换适配器的数据源        adapter.swapCursor(cursor);    }

使用SimpleCursorAdapter时,表中必须存在_id字段,否则报错,因为这个适配器内部会自动寻找_id字段的值.
//打开数据库
//第一个参数是被打开的数据库文件的路径
//第二个参数是管理游标的工厂类对象
//第三个操作数据库的方式
SQLiteDatabase db = SQLiteDatabase.openDatabase(DB_PATH, null, SQLiteDatabase.OPEN_READONLY);
然后就可以进行增删改查操作。

3.2 SQLiteOpenHelper操作内部数据库
a)定义一个类继承SQLiteOpenHelper
b)主要方法:构造方法、onCreate(SQLiteDatabase db)、onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
c) onCreate方法在该类对象调用第一次getWritableDatabase或getReadableDatabase时被系统调用,创建数据库,之后不会在调用了。
d) onUpgrade方法在版本更新时调用,主要写升级数据库的代码
使用:
dbHelper = new DBHelper(this);//初始化数据库帮助类
//因为是添加数据,所以获取到可写的数据库操作对象
SQLiteDatabase db = dbHelper.getWritableDatabase();
然后进行增删改查操作即可。

3.3数据库中事务的使用
SQLite数据库是支持事务的,事务的特性就是可以保证让某一系列的操作要么全部完成,要么一个不会完成。 比如转账场景中,银行会将转账的金额先从你的账户扣除,然后再向收款方的账户中添加等量的金额。如果这两个操作都成功了那没事,可如果当转账方的金额扣除了,而收款方收钱这个操作出意外失败了,那钱不就飞了。这种时候就需要用到事务。
下面来一个事务操作的实例:
数据库帮助类:为了简单,t_user表中只有一个_id和一个name字段

public class DbHelper extends SQLiteOpenHelper {    public DbHelper(Context context) {        super(context, "user.db", null, 1);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL("create table t_user(_id integer primary key, name text)");        db.execSQL("insert into t_user(name) values('Tom')");        db.execSQL("insert into t_user(name) values('Cat')");    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

主程序:

button1.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                SQLiteDatabase db = dbHelper.getWritableDatabase();                db.beginTransaction();//开始事务                try {                    db.delete("t_user", null, null);                    if(isException){                        throw new NullPointerException();//手动抛一个异常                    }                    db.execSQL("insert into t_user(name) values('Jack')");                    db.setTransactionSuccessful();//两个操作都执行完成,设置事务执行成功                } catch (Exception e) {                    Log.i("--", "异常");                    e.printStackTrace();                } finally{                    db.endTransaction();                }            }        });        button2.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                SQLiteDatabase db = dbHelper.getWritableDatabase();                Cursor cursor = db.rawQuery("select * from t_user", null);                while(cursor.moveToNext()){                    String name = cursor.getString(cursor.getColumnIndex("name"));                    Log.i("--", "name:" + name);                }            }        });

Android数据持久化_第1张图片
1)把isException变量设置为true,在beginTransaction之后抛一个异常,也就是说执行delete操作后就异常,setTransactionSuccessful不能执行,该事务执行失败,所以这两个操作都不会执行成功。然后再查看数据库数据:会得到开始的两条数据,如下图:
这里写图片描述

2)把isException变量设置为false,然后该事务会执行成功,到最后数据会显示新插入的一条,如下图:

3.4数据库升级需要注意的
1)不要每次升级数据库就把之前的表全部删除,在重新全部创建,这样之前的数据全部清空,用户体验为0
2)需要考虑的是,有些用户之前就安装了这个程序,有些用户是新用户
3)最后的结果必须是不管是新用户还是老用户,升级之后数据库都是最新的

数据库升级实例:
需求1:还是上面那个数据库,现在需求是数据库更新到版本2,新增一个表t_friend。
实现1:看注释

public class DbHelper extends SQLiteOpenHelper {    private final String CREATE_USER = "create table t_user(_id integer primary key, name text)";       //更新操作1:--->数据库更新到版本2,新增一个表    private final String CREATE_FRIEND = "create table t_friend(_id integer primary key, firend_id integer, name text)";        public DbHelper(Context context) {        super(context, "user.db", null, 1);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_USER);        db.execSQL("insert into t_user(name) values('Tom')");        db.execSQL("insert into t_user(name) values('Cat')");               //数据库更新,注意:这个方法只用直接用第二版的用户才会执行,        //所以在onUpgrade里需要执行一些操作        db.execSQL(CREATE_FRIEND);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        switch (oldVersion) {        case 1:            db.execSQL(CREATE_FRIEND);//这就是说,如果是老用户,该语句会得到执行,所以也就升级了         }    }}

需求2:在t_user表中添加一个字段friend_id

@Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        switch (oldVersion) {        case 1:            db.execSQL(CREATE_FRIEND);//这就是说,如果是老用户,该语句会得到执行,所以也就升级了        case 2:            //数据库更新操作2:--->在t_user表中添加一个字段friend_id            //(这个操作不更新数据库版本,所以都需要被执行,注意这里的细节,case后面都没带break,,所以这里所有的语句都会被执行            //这是为了保证在跨版本升级时,每一次的数据库修改都会被全部执行,比如当前用户是从第二版本升级到第三版本,那么case2的语句会被执行,            //如果用户直接从第一版本升级到第三版本,那么case1后面所有语句都会执行,这样,数据库都是更新到最新状态,而且表中的数据还保留着)            db.execSQL("alter table t_user add column friend_id integer");        }}

源码下载

更多相关文章

  1. 【Android】win10操作系统下Android开发环境配置
  2. Android提交数据到服务器的两种方式四种方法
  3. 操作android中的通讯录
  4. Android 数据存储之SQLite数据库存储
  5. Android数据解析出错com.android.volley.NoConnectionError: jav
  6. Android手势操作示例(上/下/左/右的判断)
  7. 引用第三方进行Android前端与web后台的数据交互

随机推荐

  1. Android应用架构之MVVM模式
  2. Android开机自启动后台服务-RECEIVE_BOOT
  3. Android CTS(兼容性测试)整个流程
  4. 【读书笔记】【Android(安卓)开发艺术探
  5. android EditTextDialog与软键盘适配(QVGA
  6. Eclipse导入的Android项目没有android报
  7. android每日一问【2011-8-27】
  8. 要学习的知识—做个笔记方便查找
  9. Android 数据操作之SQLiteDatabase
  10. 关于android 4.1源码调整asset相关目录的