美文网首页
Android学习笔记之数据存储

Android学习笔记之数据存储

作者: sssssss_ | 来源:发表于2018-10-21 15:47 被阅读0次

    Android中有5种数据存储方式,分别为文件存储、SQLite数据库、SharedPreferences、ContentProvider、网络。每种存储方式的特点如下:

    • File文件存储/SD卡:与Java中实现I/O的程序是完全一样的,提供openFileInput()和openFileOutput()方法来读取设备上的文件。
    • SharedPreferences存储:一种轻型的数据存储方式,常用来存储一些简单的配置信息,本质是基于XML文件存储key-value键值对数据。
    • SQLite数据库存储:一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,在存储大量复杂的关系型数据的时可以使用。
    • ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险。

    1、File文件存储/SD卡

    文件存储方式是一种较常用的方法,在Android中读取/写入文件的方法,与Java中实现I/O的程序是完全一样的,提供openFileInput()和openFileOutput()方法来读取设备上的文件。

    将数据存储到文件中:

    String data = "data to save";
    FileOutputStream out = openFileOutput("文件名", 覆盖:MODE_PRIVATE 追加:MODE_APPEND);
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
    writer.write(data);
    writer.close();
    

    从文件中读取数据:

    FileInputStream in = openFileInput("文件名");
    BufferedReader reader = new BufferedReader(new InputStreamReader());
    StringBuffer content = new StringBuffer();
    String line = "";
    while ((line.reader.readLine()) != null) {
        content.append(line);
    }
    reader.close();
    return content.toString();
    

    将数据存储到手机内存中

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    private void saveTosdcard() {
            String str = "data to save";
            //文件输出流
            FileOutputStream fos = null;
            //设置文件路径 ,第一个参数是文件保存的路径,null放在根目录下,第二个参数是文件名
            File file = new File(getExternalFilesDir(null), "/data666.txt");
            try {
                //传入参数第一是file,第二可以传boolean表示是否追加
                fos = new FileOutputStream(file,true);
                fos.write(str.getBytes());
                Toast.makeText(MainActivity.this, "保存到SD卡成功!", Toast.LENGTH_SHORT).show();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fos != null) {
                    try {
                        // 关闭输入流
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    • getExternalFilesDir(null):路径在/storage/sdcard0/Android/data/包名/files/文件名
    • Environment.getExternalStorageDirectory():路径在/storage/sdcard0/文件名
    删除getExternalFilesDir路径文件
    private void deleteSocket() {
        try {
            // 找到文件所在的路径并删除该文件
            File file = new File(getExternalFilesDir(null), "/dataSocketHiMate.txt");
            if (file.exists()) {
                file.delete();
            } else {
                Toast.makeText(MainActivity.this, "没有文件可以删除", Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2、SharedPreferences

    SharePreferences是一种轻型的数据存储方式,常用来存储一些简单的配置信息,如int、string、boolean、float和long。它的本质是基于XML文件存储key-value键值对数据。

    • 保存位置: data/data/程序包名/share_prefs/
    • 主要用途:
      1. 保存应用的设置 例如:设置静音,下次进入还是静音
      2. 判断是否是第一次登陆
      3. 保存登录用户名密码等情形

    将数据存储到SharedPreferences

    • 步骤1. 调用 getSharedPreferences() 方法获得 SharedPreferences 对象,提供两个参数,指定文件名和操作模式。MODE_PRIVATE只有当前程序才能读写。
    • 步骤2. 调用 SharedPreferences 对象的 edit() 方法来获取 SharedPreferences.Editor 对象。
    • 步骤3. 调用Edit接口的形如put某某某()方法以键值对形式保存某某某类型的数据。
    • 步骤4. 调用Edit接口的commit()方法提交键值对。
    SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
    editor.putString("name", "Tom");
    editor.putInt("age", 28);
    editor.putBoolean("married", false);
    editor.remove("married");
    editor.commit();
    

    从SharedPreferences中读取数据

    SharedPreferences pref  = getSharedPreferences("data",MODE_PRIVATE);
    String name = pref.getString("name","默认值");
    int age = pref.getInt("age",0);
    boolean married = pref.getBoolean("married",false);
    

    3、SQLite数据库

    SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,在存储大量复杂的关系型数据的时可以使用,比前面学过的只适用于存储简单数据的两种存储方式要好很多。

    创建数据库

    自定义帮助类并继承SQLiteOpenHelper,并重写两个方法:onCreate()和 onUpgrade(),分别在这两个方法中去实现创建、升级数据库的逻辑。还需要一个构造方法,这里用含有四个参数的构造方法就可以

    public class MyDatabaseHelper extends SQLiteOpenHelper {
        private Context mContext;
        public static final String CREATE_BOOK = "create table Book(" +
                "id integer primary key autoincrement," +
                "author text," +
                "price readl," +
                "price integer," +
                "name text)";
        public MyDatabaseHelper(Context context, String name,
                                SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
            mContext = context;
        }
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_BOOK);
        }
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            //升级数据库的话先修改版本号
            //drop删除表,delete是删除数据
            db.execSQL("drop table if exists Book");
            onCreate(db);
        }
    }
    

    数据库进行增删改查的操作

    public class Main2Activity extends AppCompatActivity {
        private MyDatabaseHelper dbHepler;
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            dbHepler = new MyDatabaseHelper(this, "BookStore.db", null, 1);
            //都是打开和创建,区别在于空间满的情况w是出现异常,R是只读
            //dbHepler.getWritableDatabase();
            dbHepler.getReadableDatabase();
            SQLiteDatabase db = dbHepler.getWritableDatabase();
    
            //添加
            ContentValues values = new ContentValues();
            values.put("name", "tom");
            values.put("pages", 464);
            values.put("price", 14.23);
            db.insert("Book", null, values);
            values.clear();
            //更新
            ContentValues values = new ContentValues();
            values.put("name", "HHH");
            db.update("Book", values, "price>?", new String[]{"10"});
            //删除
            db.delete("Book",  "price>?", new String[]{"10"});
            //查询
            Cursor c = db.query("Book",null,null,null,null,null,null);
            String s = c.getString(c.getColumnIndex("name"));
            c.close();
        }
    }
    

    sqlite数据导出到csv、txt

    String sql = "select * from location";
    Cursor cursor = db.rawQuery(sql, null);
    //如果要其他格式的话,只需修改文件后缀名即可
    ExportToCSV(cursor, "test666.csv");
    

    核心代码块ExportToCSV()

    private void ExportToCSV(Cursor c, String fileName) {
            int rowCount = 0;
            int colCount = 0;
            FileWriter fw;
            BufferedWriter bfw;
            //获取SD卡路径
            File sdCardDir = Environment.getExternalStorageDirectory();
            File saveFile = new File(sdCardDir, fileName);
            try {
                rowCount = c.getCount();
                colCount = c.getColumnCount();
                fw = new FileWriter(saveFile);
                bfw = new BufferedWriter(fw);
                if (rowCount > 0) {
                    c.moveToFirst();
                    // 写入表头
                    for (int i = 0; i < colCount; i++) {
                        if (i != colCount - 1)
                            bfw.write(c.getColumnName(i) + ',');
                        else
                            bfw.write(c.getColumnName(i));
                    }
    
                    // 写好表头后换行
                    bfw.newLine();
                    // 写入数据
                    for (int i = 0; i < rowCount; i++) {
                        c.moveToPosition(i);
                        Log.d(TAG, "正在导出第" + (i + 1) + "条");
                        for (int j = 0; j < colCount; j++) {
                            if (j != colCount - 1) {
                                bfw.write(c.getString(j) + ',');
                            } else
                                bfw.write(c.getString(j));
                        }
                        // 写好每条记录后换行
                        bfw.newLine();
                    }
                }
                // 将缓存数据写入文件
                bfw.flush();
                Log.d(TAG, "ExportToCSV: " + bfw.toString());
                // 释放缓存
                bfw.close();
                Log.d(TAG, "导出完毕!");
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                c.close();
            }
        }
    

    4、ContentProvider

    并不能用户存储数据。主要用于不同应用程序之间共享数据,只是为我们存储以及添加数据制定统一的接口而已。

    5、网络存储数据

    通过网络上提供的存储空间来上传(存储)或下载(获取)我们存储在网络空间中的数据信息

    6、共享数据的方式

    1.File, 2.Sqlite,3.Content Provider,4.Service,5.Broadcast Receiver,6.Intent

    7、了解SQLite中的事务处理吗?是如何做的?

    使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。多用于大量数据操作时,能明显减少耗时。

     SQLiteDatabase db = dbHepler.getWritableDatabase();
     db.beginTransaction();//开始事务
     try{    
         db.execSQL(...);  
         db.execSQL(...); 
         //调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务  
         db.setTransactionSuccessful(); 
    } finally{ 
        //由事务的标志决定是提交事务,还是回滚事务  
        db.endTransaction();
    } 
    db.close();
    

    8、事务的属性

    • 原子性(Atomicity):确保工作单位内的所有操作都成功完成,否则,事务会在出现故障时终止,之前的操作也会回滚到以前的状态。
    • 一致性(Consistency):确保数据库在成功提交的事务上正确地改变状态。
    • 隔离性(Isolation):使事务操作相互独立和透明。
    • 持久性(Durability):确保已提交事务的结果或效果在系统发生故障的情况下仍然存在。

    9、使用SQLite做批量操作有什么好的方法吗?

    即使用事务处理进行优化,默认SQLite的数据库插入操作,如果没有采用事务的话,它每次写入提交,就会触发一次事务操作,而这样几千条的数据,就会触发几千个事务的操作,这就是时间耗费的根源

    10、如果现在要删除SQLite中表的一个字段如何做?

    SQLite数据库只允许增加表字段而不允许修改和删除表字段,只能采取复制表思想,即创建一个新表保留原表想要的字段、再将原表删除。

    11、使用SQLite时会有哪些优化操作?

    1. 使用事务做批量操作:具体操作见上。
    2. 及时关闭Cursor,避免内存泄漏。
    3. 耗时操作异步化:数据库的操作属于本地IO,通常比较耗时,建议将这些耗时操作放入异步线程中处理。
    4. ContentValues的容量调整:ContentValues内部采用HashMap来存储Key-Value数据,ContentValues初始容量为8,扩容时翻倍。因此建议对ContentValues填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作
    5. 使用索引加快检索速度:对于查询操作量级较大、业务对要求查询要求较高的推荐使用索引

    12、Android 中有哪几种解析xml的类,官方推荐哪种?以及它们的原理和区别。

    Android 提供了三种解析XML的方式:SAX(Simple API XML)DOM(Document Object Model)Pull解析

    • Dom解析:将XML文件的所有内容读取到内存中(内存的消耗比较大),然后允许您使用DOM API遍历XML树、检索所需的数据。
    • Sax解析:Sax是一个解析速度快并且占用内存少的xml解析器,Sax解析XML文件采用的是事件驱动,它并不需要解析完整个文档,而是按内容顺序解析文档的过程。
    • Pull解析:Pull解析器的运行方式与 Sax 解析器相似。它提供了类似的事件,可以使用一个switch对感兴趣的事件进行处理。

    本文参考资料:

    相关文章

      网友评论

          本文标题:Android学习笔记之数据存储

          本文链接:https://www.haomeiwen.com/subject/haebzftx.html