美文网首页
Android数据存储方式

Android数据存储方式

作者: zoky_ | 来源:发表于2017-01-15 00:54 被阅读0次

    一、使用SharedPreferences存储数据

    默认存储路径:/data/data/<PackageName>/shared_prefs

    SharedPreferences是一个较轻量级的存储数据的方法,适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。

    核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data/<package name>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,
    该方法中name表示要操作的xml文件名,第二个参数为设置读写模式,有以下三种选择:

    • Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。
    • Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写。
    • Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读,写。

    而编辑接口Editor有如下主要重要方法:

    • SharedPreferences.Editor clear():清空SharedPreferences里所有数据

    • ** SharedPreferences.Editor putXxx(String key , xxx value):** 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据

    • ** SharedPreferences.Editor remove()**: 删除SharedPreferences中指定key对应的数据项

    • ** boolean commit()**: 当Editor编辑完成后,使用该方法提交修改

    读写其他应用的SharedPreferences: 步骤如下

    1. 在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取

    2. 创建其他应用程序对应的Context:

      Context pvCount = createPackageContext("com.tony.app",
      Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名

    3. 使用其他程序的Context获取对应的SharedPreferences

      SharedPreferences read = pvCount.getSharedPreferences("lock",
      Context.MODE_WORLD_READABLE);

    4. 如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。

    SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。另外需要注意的一点是sharePreference在多进程的情况下会失效。

    二、SQLite数据库存储数据

    默认存储路径:/data/data/<PackageName>/databases

    SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据。

    SQLiteDatabase类为我们提供了很多种方法,上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用

    1 db.executeSQL(String sql);
    2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集

     @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
              
            //打开或创建test.db数据库  
            SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);  
            db.execSQL("DROP TABLE IF EXISTS person");  
            //创建person表  
            db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)");  
            Person person = new Person();  
            person.name = "john";  
            person.age = 30;  
            //插入数据  
            db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age});  
              
            person.name = "david";  
            person.age = 33;  
            //ContentValues以键值对的形式存放数据  
            ContentValues cv = new ContentValues();  
            cv.put("name", person.name);  
            cv.put("age", person.age);  
            //插入ContentValues中的数据  
            db.insert("person", null, cv);  
              
            cv = new ContentValues();  
            cv.put("age", 35);  
            //更新数据  
            db.update("person", cv, "name = ?", new String[]{"john"});  
              
            Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"});  
            while (c.moveToNext()) {  
                int _id = c.getInt(c.getColumnIndex("_id"));  
                String name = c.getString(c.getColumnIndex("name"));  
                int age = c.getInt(c.getColumnIndex("age"));  
                Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age);  
            }  
            c.close();  
              
            //删除数据  
            db.delete("person", "age < ?", new String[]{"35"});  
              
            //关闭当前数据库  
            db.close();  
              
            //删除test.db数据库  
    //      deleteDatabase("test.db");  
        }  
    

    在执行完上面的代码后,系统就会在/data/data/[PACKAGE_NAME]/databases目录下生成一个“test.db”的数据库文件。

    上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用

    db.executeSQL(String sql);  
    db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集  
    

    来执行sql语句,
    除了统一的形式之外,他们还有各自的操作方法:

    db.insert(String table, String nullColumnHack, ContentValues values);  
    db.update(String table, Contentvalues values, String whereClause, String whereArgs);  
    db.delete(String table, String whereClause, String whereArgs);  
    

    以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样。

    下面,我们就以一个实例来讲解具体的用法,我们新建一个名为db的项目,其中DBHelper继承了SQLiteOpenHelper,作为维护和管理数据库的基类,DBManager是建立在DBHelper之上,封装了常用的业务方法,Person是我们的person表对应的JavaBean,MainActivity就是我们显示的界面。

    public class DBHelper extends SQLiteOpenHelper {  
      
        private static final String DATABASE_NAME = "test.db";  
        private static final int DATABASE_VERSION = 1;  
          
        public DBHelper(Context context) {  
            //CursorFactory设置为null,使用默认值  
            super(context, DATABASE_NAME, null, DATABASE_VERSION);  
        }  
      
        //数据库第一次被创建时onCreate会被调用  
        @Override  
        public void onCreate(SQLiteDatabase db) {  
            db.execSQL("CREATE TABLE IF NOT EXISTS person" +  
                    "(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)");  
        }  
      
        //如果DATABASE_VERSION值被改为2,系统发现现有数据库版本不同,即会调用onUpgrade  
        @Override  
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
            db.execSQL("ALTER TABLE person ADD COLUMN other STRING");  
        }  
    }  
    

    数据库第一次创建时onCreate方法会被调用,我们可以执行创建表的语句,当系统发现版本变化之后,会调用onUpgrade方法,我们可以执行修改表结构等语句。
    为了方便我们面向对象的使用数据,我们建一个Person类,对应person表中的字段,如下:

    public class Person {  
        public int _id;  
        public String name;  
        public int age;  
        public String info;  
          
        public Person() {  
        }  
          
        public Person(String name, int age, String info) {  
            this.name = name;  
            this.age = age;  
            this.info = info;  
        }  
    }  
    

    然后,我们需要一个DBManager,来封装我们所有的业务方法,代码如下:

    public class DBManager {  
        private DBHelper helper;  
        private SQLiteDatabase db;  
          
        public DBManager(Context context) {  
            helper = new DBHelper(context);  
            //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory);  
            //所以要确保context已初始化,我们可以把实例化DBManager的步骤放在Activity的onCreate里  
            db = helper.getWritableDatabase();  
        }  
          
        /** 
         * add persons 
         * @param persons 
         */  
        public void add(List<Person> persons) {  
            db.beginTransaction();  //开始事务  
            try {  
                for (Person person : persons) {  
                    db.execSQL("INSERT INTO person VALUES(null, ?, ?, ?)", new Object[]{person.name, person.age, person.info});  
                }  
                db.setTransactionSuccessful();  //设置事务成功完成  
            } finally {  
                db.endTransaction();    //结束事务  
            }  
        }  
          
        /** 
         * update person's age 
         * @param person 
         */  
        public void updateAge(Person person) {  
            ContentValues cv = new ContentValues();  
            cv.put("age", person.age);  
            db.update("person", cv, "name = ?", new String[]{person.name});  
        }  
          
        /** 
         * delete old person 
         * @param person 
         */  
        public void deleteOldPerson(Person person) {  
            db.delete("person", "age >= ?", new String[]{String.valueOf(person.age)});  
        }  
          
        /** 
         * query all persons, return list 
         * @return List<Person> 
         */  
        public List<Person> query() {  
            ArrayList<Person> persons = new ArrayList<Person>();  
            Cursor c = queryTheCursor();  
            while (c.moveToNext()) {  
                Person person = new Person();  
                person._id = c.getInt(c.getColumnIndex("_id"));  
                person.name = c.getString(c.getColumnIndex("name"));  
                person.age = c.getInt(c.getColumnIndex("age"));  
                person.info = c.getString(c.getColumnIndex("info"));  
                persons.add(person);  
            }  
            c.close();  
            return persons;  
        }  
          
        /** 
         * query all persons, return cursor 
         * @return  Cursor 
         */  
        public Cursor queryTheCursor() {  
            Cursor c = db.rawQuery("SELECT * FROM person", null);  
            return c;  
        }  
          
        /** 
         * close database 
         */  
        public void closeDB() {  
            db.close();  
        }  
    }  
    

    我们在DBManager构造方法中实例化DBHelper并获取一个SQLiteDatabase对象,作为整个应用的数据库实例;在添加多个Person信息时,我们采用了事务处理,确保数据完整性;最后我们提供了一个closeDB方法,释放数据库资源,这一个步骤在我们整个应用关闭时执行,这个环节容易被忘记

    其他具体详见 相关博客: http://blog.csdn.net/liuhe688/article/details/6715983/

    现在Android在SQLite数据存储方面出现了很多的ORM框架:ORMLite、greendao、ormndroid、androrm、ActiveAndroid,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。这些都极大的提高了我们的开发数据库的效率,也值得我们深入学习。

    三、文件存储数据

    默认存储路径:/data/data/<PackageName>/files

    核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选:

             MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可   以使用Context.MODE_APPEND
    
             MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
    
             MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
    
             MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
    

    除此之外,Context还提供了如下几个重要的方法:

             getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录
    
             File getFilesDir():获取该应用程序的数据文件夹得绝对路径
    
             String[] fileList():返回该应用数据文件夹的全部文件    
    

    写入文件:

        public void save(){
          String data = "save something here";
          FileOutputStream out = null;
          ButteredWriter writer = null;
          try{
                out = openFileOutput("data",Context.MODE_PRIVATE);
                writer = new ButteredWriter(new OutputSreamWriter(out));
                writer.write(data);
          }catch(IOException e){
                e.printStackTrace();
          }finally{
                try{
                      if(writer!=null){
                            writer.close();
                      }
                }catch(IOException e){
                      e.printStackTrace();
           }
    }
    

    读取文件数据:

    public String load(){
          FileInputStream in = null;
          ButteredReader reader = null;
          StringBuilder builder = new StringBuilder();
          try{
                in = openFileInput("data");
                reader = new ButteredReader(new InputStreamReader(in));
                String line= "";
                while((line = reader.readline()) != null){
                       builder.append();
                }
          }catch(IOException e){
                e.printStackTrace();
          }finally{
                if(reader != null){
                        try{
                              reader.close();
                        }catch(IOException e){
                              e.printStackTrace();
                        }
                 }
          }
    }
    

    读写sdcard上的文件

    其中读写步骤按如下进行:

    1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true

    Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

    2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录

    3、使用IO流操作SD卡上的文件

    注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡

    必须在AndroidManifest.xml上配置读写SD卡的权限

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    

    四、ContentProvider存储数据

    ContentProvider主要用于不同的程序之间实现数据共享的功能。详见Android四大组件介绍的内容

    五、网络存储

    这个很好理解,就是将数据上传到服务器,在需要的时候再将它通过网络读取下来即可。

    相关文章

      网友评论

          本文标题:Android数据存储方式

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