精华内容
下载资源
问答
  • 3种数据持久化: File:openFileInput(String fileName)、openFileOutput(String fileName, int mode) 不对存储的内容进行任何的格式化处理,比较合适存储一些简单的文本数据或二进制数据 SharedPreferences 使用...

    3种数据持久化:

    • File:openFileInput(String fileName)、openFileOutput(String fileName, int mode)

    不对存储的内容进行任何的格式化处理,比较合适存储一些简单的文本数据或二进制数据

    • SharedPreferences

    使用键值对的方式来存储数据,保存数据更加方便。数据以明文的方式保存在文件中,需要加密,一般保存应用设置。

    • SQLite 继承SqLiteOpenHelper类创建数据库,

    可以保存大量复杂的关系型数据 

    账号密码自动登陆:

    在项目中,我们一般使用SharePrefences实现自动登录的功能,在登录成功后,将数据(用户名,密码)保存在SharePrefences中,然后再次进入app时,判断SharePrefences中有无数据,有的话就跳到主页面,没有的话就跳到登录页。

    SharedPreferences 的源码实现:

    SharedPreferences 是线程安全的。

    final class SharedPreferencesImpl implements SharedPreferences {
      // 1、使用注释标记锁的顺序
      // Lock ordering rules:
      //  - acquire SharedPreferencesImpl.mLock before EditorImpl.mLock
      //  - acquire mWritingToDiskLock before EditorImpl.mLock
     
      // 2、通过注解标记持有的是哪把锁
      @GuardedBy("mLock")
      private Map<String, Object> mMap;
     
      @GuardedBy("mWritingToDiskLock")
      private long mDiskStateGeneration;
     
      public final class EditorImpl implements Editor {
        @GuardedBy("mEditorLock")
        private final Map<String, Object> mModified = new HashMap<>();
      }
    }

    SharedPreferences 是由 Context 返回的,获取 SharedPreferences 的方法定义在抽象类 Context 中。

        public abstract SharedPreferences getSharedPreferences(String name, int mode);
        public abstract SharedPreferences getSharedPreferences(File file, int mode);

    第一个方法是我们常用的,只要传入文件名,SP会自动寻找已有文件或创建,第二个是我们传入的文件。

    所以 SharedPreferences 的操作,本质上就是对文件的操作,使用SharedPreferences时,只有第一次读取数据是有概率卡主线程几十到几百毫秒,而之后的读取时间几乎可以忽略不计。最后会落实到一个 xml 文件上。

        @Override
        public File getSharedPreferencesPath(String name) {
            return makeFilename(getPreferencesDir(), name + ".xml");
        }

    标准路径在 /data/data/应用包名/shared_prefs 文件夹中,且都是 xml 文件。

    commit 和 apply 的对比

    EditorImpl 内部有一个内存缓存,用来保存用户修改后的操作:

        private final Map<String, Object> mModified = Maps.newHashMap();

    在执行 commit 或者 apply 前,比如editor.putString("Key","Value")会把修改存储在 mModified 中。

        public Editor putString(String key, @Nullable String value) {
            synchronized (this) {
                mModified.put(key, value);
                    return this;
                }
            }
        }

    commit(同步):构造一个MemoryCommitResult来进行结果投递,在post任务以后会直接在当前线程进行wait。

    apply(异步):构造一个MemoryCommitResult来调度IO(QueuedWork提供了singleThreadExecutor),apply()不会等待,而由QueuedWork的waitToFinish()方法的调用者(ActivityThread)来保证在某些时间点等待task的完成。

    QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);

    QueuedWork:一个内部工具类,用于跟踪那些未完成的或尚未结束的全局任务。由 waitToFinish 方法保证执行,在 Activity onStop 以及 Service 处理 onStop,onStartCommand 时等待写入操作,所有排队的异步任务都在一个独立、专用的线程上处理。平时使用的时候,尽量使用 apply 避免卡住主线程。

    apply方法造成的ANR:

    在apply()方法中,首先会创建一个等待锁,最终更新文件的任务会交给QueuedWork.singleThreadExecutor()单个线程或者HandlerThread去执行,当文件更新完毕后会释放锁。 但当Activity.onStop()以及Service处理onStop等相关方法时,则会执行 QueuedWork.waitToFinish()等待所有的等待锁释放,因此如果SharedPreferences一直没有完成更新任务,有可能会导致卡在主线程,最终超时导致ANR。

    加载 xml 数据文件

     SharedPreferences 的加载流程,就是把文件的内容载入内存的过程。

        private void loadFromDisk() {
            ...
            str = new BufferedInputStream(
                    new FileInputStream(mFile), 16*1024);
            map = XmlUtils.readMapXml(str);
            ...
        }

    本质上,就是读取一个 xml 文件,被内容解析为 Map 对象。这个 map 包含了我们之前保存的所有键值对的数据。 

    SharedPreferences 的读取非常快,载入完成后,后面的读操作都是针对 mMap 的,响应速度是内存级别的非常快。

    SharedPreferences 不存放大量数据原因:

    • apply操作耗时过久会导致ANR
    • 如果数据量很大的话,返回的map对象会占很大一块内存
    展开全文
  • Android数据持久化SharedPreferences浅析

    千次阅读 2019-01-20 10:24:53
     本文为自己多年来在Android实战开发过程中总结归纳的一些常见问题,现在分享出来希望对初学者有所...SharedPreferences 是Android平台上一个轻量级的存储类,主要是保存一些常用的配置比如窗口状态,一般在Acti...

     本文为自己多年来在Android实战开发过程中总结归纳的一些常见问题,现在分享出来希望对初学者有所帮助。

    本文出自门心叼龙的博客,转载请注明出处: https://blog.csdn.net/geduo_83/article/details/86559705

    SharedPreferences 是Android平台上一个轻量级的存储类,主要是保存一些常用的配置比如窗口状态,一般在Activity中 重载窗口状态onSaveInstanceState保存一般使用SharedPreferences完成,它提供了Android平台常规的Long长 整形、Int整形、String字符串型的保存。   
    它是什么样的 处理方式呢? SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问,android123提示最 终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml 处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好。
    它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息,其存储位置在/data/data/<包名>/shared_prefs目录下。 SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。 
    实现SharedPreferences存储的步骤如下:    

    • 1. 根据Context获取SharedPreferences对象    
    • 2. 利用edit()方法获取Editor对象。   
    • 3. 通过Editor对象存储key-value键值对数据。 
    • 4. 通过commit()方法提交数据。

     下面是示例代码: 

    public class MainActivity extends Activity {
     
     @Override
          public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.main);
             
             //获取SharedPreferences对象
             Context ctx = MainActivity.this;
             SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE);
             //存入数据
             Editor editor = sp.edit();
             editor.putString("STRING_KEY", "string");
             editor.putInt("INT_KEY", 0);
             editor.putBoolean("BOOLEAN_KEY", true);
             editor.commit();
            } 
    }


     

    展开全文
  • Android数据持久

    2020-08-11 20:17:18
    SharedPreferences是Android提供的数据持久化的一种手段,适合单进程、小批量的数据存储与访问。SharedPreferences的实现是基于单个xml文件实现的,并且,所有持久化数据都是一次性加载到内存,如果数据过大,是不...

    Android数据持久化(存储)

    1.SharedPreferences

    SharedPreferences是Android提供的数据持久化的一种手段,适合单进程、小批量的数据存储与访问。SharedPreferences的实现是基于单个xml文件实现的,并且,所有持久化数据都是一次性加载到内存,如果数据过大,是不合适采用SharedPreferences存放的。而适用的场景是单进程的原因同样如此,由于Android原生的文件访问并不支持多进程互斥,所以SharePreferences也不支持,如果多个进程更新同一个xml文件,就可能存在同步不互斥问题
    基本使用,haredPreferences的实现:

    存入

        mSharedPreferences = context.getSharedPreferences("test", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = mSharedPreferences.edit();
        editor.putString(key, value);
        editor.apply();
    

    获取

        mSharedPreferences = context.getSharedPreferences("test", Context.MODE_PRIVATE);
        mSharedPreferences .getString(key, defaultValue);
    

    与SharePreferences对应的xml文件位置一般都在/data/data/包名/shared_prefs目录下,后缀一定是.xml,数据存储样式如下:

    <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    <map>
        <string name="client.no">2</string>
        <string name="login.info">{&quot;result&quot;:{&quot;account&quot;:&quot;wxx&quot;,&quot;hospitalId&quot;:4,&quot;hospitalInfo&quot;:{&quot;address&quot;:&quot;湖南省株洲市天元区001街道new&quot;,&quot;code&quot;:&quot;430211020100&quot;,&quot;contacts&quot;:&quot;修改哈哈!new&quot;,&quot;email&quot;:&quot;ylhkaixin@163.com&quot;,&quot;id&quot;:4,&quot;jzrRemark&quot;:&quot;接种点备注支付2.0测试&quot;,&quot;lat&quot;:27.841850,&quot;lng&quot;:113.136993,&quot;name&quot;:&quot;小豆苗预防接种门诊new&quot;,&quot;openId&quot;:&quot;3YddL5KzTMijwVcbsM6fkpp7p3AV9jqF9pGGkJnmRRLmjSS2tMivEhdZVGaPny&quot;,&quot;page&quot;:0,&quot;pageSize&quot;:0,&quot;postCode&quot;:&quot;522817&quot;,&quot;qq&quot;:&quot;3453241321&quot;,&quot;regionId&quot;:430211,&quot;remark&quot;:&quot;&quot;,&quot;setting&quot;:{&quot;hospitalId&quot;:4,&quot;id&quot;:4,&quot;isAppoint&quot;:1,&quot;isBeforeRemind&quot;:0,&quot;isDigital&quot;:1,&quot;isPayment&quot;:2,&quot;isPurchaseInAdvance&quot;:1,&quot;isSelectedVacc&quot;:1,&quot;isSwitch&quot;:1,&quot;isVccInventory&quot;:1,&quot;opDigitalclinic&quot;:1,&quot;opInfoConsent&quot;:1},&quot;shortName&quot;:&quot;门诊通知到了23&quot;,&quot;telephone&quot;:&quot;0731-221691778&quot;},&quot;id&quot;:19697,&quot;realName&quot;:&quot;wxx&quot;},&quot;error&quot;:0}</string>
        <string name="client.manager.host.ip">192.168.0.104</string>
        <string name="login.name">wxx</string>
        <long name="login.last.update.time" value="1594888957260" />
        <int name="client.type" value="1" />
    </map>
    

    Editor是一个接口,这里的实现是一个EditorImpl对象,它首先批量预处理更新操作,之后再提交更新,在提交事务的时候有两种方式,一种是apply,另一种commit,两者的区别在于:何时将数据持久化到xml文件,前者是异步的,后者是同步的。Google推荐使用前一种,因为,就单进程而言,只要保证内存缓存正确就能保证运行时数据的正确性,而持久化,不必太及时

    SharedPreferences存储的特点

    1、sharedPerferences是一种轻量级的存储方式。
    
    2、只支持JAVA基本数据类型,不支持自定义的数据类型。
    
    3、应用内数据可以共享。
    
    4、使用简单,方便。
    

    getSharedPreferences()源码分析

     public SharedPreferences getSharedPreferences(String name, int mode) {
         Class var4 = ContextImpl.class;
         SharedPreferencesImpl sp;
         synchronized(ContextImpl.class) {
             //一个全局的静态对象,定义如下:private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;
             if (sSharedPrefs == null) {
                 sSharedPrefs = new ArrayMap();
             }
             //根据应用程序的包名在程序的执行环境中取到该应用程序对应的SharedPreferences文件组
             String packageName = this.getPackageName();
             ArrayMap<String, SharedPreferencesImpl> packagePrefs = (ArrayMap)sSharedPrefs.get(packageName);
             //如果不存在就创建,并缓存到全局的ArrayMap(sSharedPrefs)中
             if (packagePrefs == null) {
                 packagePrefs = new ArrayMap();
                 sSharedPrefs.put(packageName, packagePrefs);
             }
    
             if (this.mPackageInfo.getApplicationInfo().targetSdkVersion < 19 && name == null) {
                 name = "null";
             }
            //根据文件的Name去拿到对应的SharedPreferencesImpl对象,如果没有就创建,并放入到自己的上一级缓存packagePrefs中
             sp = (SharedPreferencesImpl)packagePrefs.get(name);
             if (sp == null) {
                 File prefsFile = this.getSharedPrefsFile(name);
                 sp = new SharedPreferencesImpl(prefsFile, mode);
                 packagePrefs.put(name, sp);
                 return sp;
             }
         }
    
         if ((mode & 4) != 0 || this.getApplicationInfo().targetSdkVersion < 11) {
             sp.startReloadIfChangedUnexpectedly();
         }
    
         return sp;
     }
    
    

    总结起来就是:由于ContextImpl是应用程序的执行环境,每个应用程序里面可以包含有多个SharedPreference文件。因此,为了更好的定位SharedPreference文件,首先根据应用程序进行筛选,得到ArrayMap 然后再通过SharedPreference文件名进行筛选,得到SharedPreferencesImpl。可以看到,SharedPreferencesImpl只会被创建一次,之后会被保存在缓存中,后续的获取操作都是从缓存中获取SharedPreferencesImpl实例对象。

    2.file

    Internal Storage VS External Storage
    在使用File存储App数据时,我们需要了解Android系统的存储系统。Android的存储分为内部存储和外部存储。

    所有的Android设备都有两块存储区域:Internal Storage和External Storage。它们的名称来源于早期的Android系统,那时候大家的手机都内置(Permanent)一块较小存储板(即Internal Storage),并配上一个的外置的(Removable)储存卡(即External Storage)。后来部分手机开始将最初定义的“Internal Storage”,即内置存储,分成Internal和External两部分。这样一来就算没有外置储存,手机也有Internal和External两块存储区域。

    Internal Storage

    • /data/data/package name/files
    • /data/data/package name/cache
    • /data/data/package name/databases
    • /data/data/package name/shared_prefs

    External Storage

    由于Android系统的厂商比较多,对于外部存储目录的定义有所不同,可能在根目录下的mnt,sdcard和storage下。以storage为例,打开emulated/0目录,外部存储目录就出现了。虽然可以通过多种路径打开外部存储文件,但是最终他们的路径是相同的:

    在这里插入图片描述
    在这里插入图片描述

    对比下来External有以下几点优点:

    通过USB可以将数据传到电脑上
    可以与其他App共享数据
    在Android/data/package name/路径以外的数据不会因为程序卸载而被删除
    缺点:

    外置存储有时不可用
    在非root情况下,数据无法私有化
    在Android/data/package name/路径以外存储数据需要申请写入权限

    Internal Storage存储数据

    Android数据存储之File方法getFilesDir()和openFileOutput(String name)返回的路径相同
    Android数据存储之SharedPreferences
    Databases(数据库)
    Content Provider

    External Storage存储数据
    首先我们要获取外部存储目标文件的路径:

    目标目录 获取方法
    公有目录九大文件 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
    公有根目录 Environment.getExternalStorageDirectory()
    私有目录file Context.getExternalFilesDir(Environment.DIRECTORY_MUSIC)
    私有目录cache Context.getExternalCacheDir()
    然后确定自己需要创建的文件名,结合上面的到的路径,创建一个File对象:

    private void saveExternal(String str) {
            FileOutputStream outputStream = null;
            DataOutputStream out = null;
            try{
                try{
                    outputStream = new FileOutputStream(
                            new File(Environment.getExternalStorageDirectory(),
                                    "data_external.dat"));
                    out = new DataOutputStream(new BufferedOutputStream(outputStream));
                    out.writeUTF(str);
                }finally {
                    out.close();
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
    }
    

    上述表格中的方法,有两个方法需要传入一个String类型的参数,这个参数我们使用了Environment中的常量,参数的意思是我们要访问这个路径下的哪个文件夹

    App数据清理
    Android系统默认数据清理的路径是,内部存储目录中相应的cache文件夹中的文件和外部存储中相应的cache文件夹中的文件。

    细节
    内部存储

    你的app的internal storage 目录是以你的app的包名作为标识存放在Android文件系统的特定目录下[data/data/com.example.xx]。 从技术上讲,如果你设置文件为可读的,那么其他app就可以读取你的internal文件。然而,其他app需要知道你的包名与文件名。若是你没有设置为可读或者可写,其他app是没有办法读写的。因此只要你使用MODE_PRIVATE ,那么这些文件就不可能被其他app所访问。

    内部存储在你的APP卸载的时候,会一块被删除,因此,我们可以在cache目录里面放置我们的图片缓存,而且cache与files的差别在于,如果手机的内部存储空间不够了,会自行选择cache目录进行删除,因此,不要把重要的文件放在cache文件里面,可以放置在files里面,因为这个文件只有在APP被卸载的时候才会被删除。还有要注意的一点是,如果应用程序是更新操作,内部存储不会被删除,区别于被用户手动卸载。

    外部存储
    不管是使用 getExternalStoragePublicDirectory() 来存储可以共享的文件,还是使用 getExternalFilesDir() 来储存那些对于app来说是私有的文件,有一点很重要,那就是要使用那些类似DIRECTORY_PICTURES 的API的常量。那些目录类型参数可以确保那些文件被系统正确的对待。例如,那些以DIRECTORY_RINGTONES 类型保存的文件就会被系统的media scanner认为是ringtone而不是音乐。

    清除数据、清除缓存的区别
    清除数据主要是清除用户配置,比如SharedPreferences、数据库等等,这些数据都是在程序运行过程中保存的用户配置信息,清除数据后,下次进入程序就和第一次进入程序时一样
    缓存是程序运行时的临时存储空间,它可以存放从网络下载的临时图片,从用户的角度出发清除缓存对用户并没有太大的影响,但是清除缓存后用户再次使用该APP时,由于本地缓存已经被清理,所有的数据需要重新从网络上获取。为了在清除缓存的时候能够正常清除与应用相关的缓存,请将缓存文件存放在getCacheDir()或者 getExternalCacheDir()路径下

    3.SQLite存储数据

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

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

    1 db.executeSQL(String sql);
    2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集
    除了统一的形式之外,他们还有各自的操作方法:

    1 db.insert(String table, String nullColumnHack, ContentValues values);
    2 db.update(String table, Contentvalues values, String whereClause, String whereArgs);
    3 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方法的参数也是一样

    数据的添加

    1.使用insert方法

    ContentValues cv = new ContentValues();//实例化一个ContentValues用来装载待插入的数据
     cv.put("title","you are beautiful");//添加title
     cv.put("weather","sun"); //添加weather
     cv.put("context","xxxx"); //添加context
     String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                            .format(new Date());
     cv.put("publish ",publish); //添加publish
     db.insert("diary",null,cv);//执行插入操作 
    

    2.使用execSQL方式来实现

    String sql = "insert into user(username,password) values (‘Jack Johnson’,‘iLovePopMuisc’);//插入操作的SQL语句
    db.execSQL(sql);//执行SQL语句

    数据的删除
    同样有2种方式可以实现

    String whereClause = "username=?";//删除的条件
    String[] whereArgs = {"Jack Johnson"};//删除的条件参数
    db.delete("user",whereClause,whereArgs);//执行删除
    

    使用execSQL方式的实现

    String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句
    db.execSQL(sql);//执行删除操作
    

    数据修改

    同上,仍是2种方式

    ContentValues cv = new ContentValues();//实例化ContentValues
    cv.put("password","iHatePopMusic");//添加要更改的字段及内容
    String whereClause = "username=?";//修改条件
    String[] whereArgs = {"Jack Johnson"};//修改条件的参数
    db.update("user",cv,whereClause,whereArgs);//执行修改
    

    使用execSQL方式的实现

    String sql = "update user set password = 'iHatePopMusic' where username='JackJohnson'";//修改的SQL语句
    db.execSQL(sql);//执行修改
    

    数据查询

    db.rawQuery(String sql, String[] selectionArgs);  
     db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);  
     db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);  
     db.query(String distinct, String table, String[] columns, String selection, 
     String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
    

    上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集;

    各参数说明:
    table:表名称
    colums:表示要查询的列所有名称集
    selection:表示WHERE之后的条件语句,可以使用占位符
    selectionArgs:条件语句的参数数组
    groupBy:指定分组的列名
    having:指定分组条件,配合groupBy使用
    orderBy:y指定排序的列名
    limit:指定分页参数
    distinct:指定“true”或“false”表示要不要过滤重复值
    Cursor:返回值,相当于结果集ResultSet

    最后,他们同时返回一个Cursor对象,代表数据集的游标,有点类似于JavaSE中的ResultSet。下面是Cursor对象的常用方法:

     c.move(int offset); //以当前位置为参考,移动到指定行  
     c.moveToFirst();    //移动到第一行  
     c.moveToLast();     //移动到最后一行  
     c.moveToPosition(int position); //移动到指定行  
     c.moveToPrevious(); //移动到前一行  
     c.moveToNext();     //移动到下一行  
     c.isFirst();        //是否指向第一条  
     c.isLast();     //是否指向最后一条  
     c.isBeforeFirst();  //是否指向第一条之前  
     c.isAfterLast();    //是否指向最后一条之后  
     c.isNull(int columnIndex);  //指定列是否为空(列基数为0)  
     c.isClosed();       //游标是否已关闭  
     c.getCount();       //总数据项数  
     c.getPosition();    //返回当前游标所指向的行数  
     c.getColumnIndex(String columnName);//返回某列名对应的列索引值  
     c.getString(int columnIndex);   //返回当前行指定列的值
    

    实现代码

    String[] params =  {12345,123456};
    Cursor cursor = db.query("user",columns,"ID=?",params,null,null,null);//查询并获得游标
    if(cursor.moveToFirst()){//判断游标是否为空
        for(int i=0;i<cursor.getCount();i++){
            cursor.move(i);//移动到指定记录
            String username = cursor.getString(cursor.getColumnIndex("username");
            String password = cursor.getString(cursor.getColumnIndex("password"));
        }
    }
    

    通过rawQuery实现的带参数查询

    Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");
    //Cursor c = db.rawQuery("s name, inventory FROM mytable where ID=?",new Stirng[]{"123456"});     
    result.moveToFirst(); 
    while (!result.isAfterLast()) { 
        int id=result.getInt(0); 
        String name=result.getString(1); 
        int inventory=result.getInt(2); 
        // do something useful with these 
        result.moveToNext(); 
     } 
     result.close();
    

    我们完成了对数据库的操作后,记得调用SQLiteDatabase的close()方法释放数据库连接,否则容易出现SQLiteException。

    展开全文
  • 为什么要实现数据持久化? 比如:对象Student中有参数name、sex、age等,在应用开发中可以创建一个Student对象并给其参数赋值,该方式用于存储暂时\瞬时的数据,当退出程序或资源被回收后所保存的数据就消失了,...

    在应用开发中,不可避免要无时无刻地和数据打交道。


    为什么要实现数据持久化?

    比如:对象Student中有参数name、sex、age等,在应用开发中可以创建一个Student对象并给其参数赋值,该方式用于存储暂时\瞬时的数据,当退出程序或资源被回收后所保存的数据就消失了,因此当我们开发中需要保存用户登录的账号或密码、保存用户设置等重要信息时,数据持久化就可以帮助我们实现这一需求。


    那么,如何实现数据持久化?

    在开发中要实现数据持久化,总的来说,无非就是要实现程序退出或杀死后,之前的数据能够保留下来不被清除掉。


    下面,介绍实现数据持久化的三种方式及其具体用法。

    实现数据持久化的三种方式:文件存储、SharedPreferences存储、数据库存储。


    1、文件存储

    方式:把所要保存一些文本数据存储到手机的内存中,当有需要的时候读取出来,默认的存储到data/data/<package name> /files目录下,因此当程序被卸载时所在的目录文件都会被删除,这些数据也会随着消失。


    实现原理:

    <1>存储数据:通过Context类中所提供的openFileOutput()方法:

    public FileOutputStream openFileOutput(String name, int mode)

    方法openFileOutput返回的数据是FileOutputStream,方法传入的第一个参数是文件名,第二个参数是文件的操作方式:

    MODE_PRIVATE(当指定同样文件名时会覆盖原文件中的内容)、MODE_APPEND(当该文件已存在时就往文件中追加内容,不会创建新文件)。

    	public void saveData(String inputText) {
    		FileOutputStream out = null;
    		BufferedWriter writer = null;
    		if (inputText != null && !TextUtils.isEmpty(inputText)) {
    			try {
    				out = openFileOutput("save", Context.MODE_PRIVATE);
    				writer = new BufferedWriter(new OutputStreamWriter(out));
    				writer.write(inputText);
    			} catch (FileNotFoundException e) {
    				e.printStackTrace();
    			} catch (IOException e) {
    				e.printStackTrace();
    			} finally {
    				try {
    					if (out != null) {
    						out.close();
    					}
    					if (writer != null) {
    						writer.close();
    					}
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}

    <2>读取数据:通过Context类中所提供的openFileInput()方法:

    public FileInputStream openFileInput(String name)

    方法openFileInput返回的数据是FileInputStream,方法传入的第一个参数是所要读取的文件名

    	public String readData() {
    		FileInputStream in = null;
    		BufferedReader reader = null;
    		try {
    			in = openFileInput("save");
    			reader = new BufferedReader(new InputStreamReader(in));
    			StringBuffer buffer = new StringBuffer();
    			String len = "";
    			while ((len = reader.readLine()) != null) {
    				buffer.append(len);
    			}
    			return buffer.toString();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				if (in != null) {
    					in.close();
    				}
    				if (reader != null) {
    					reader.close();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return "";
    	}
    注:在涉及到读写操作中记得在AndroidManifest中添加上读写权限:

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


    2、SharedPreferences存储

    方式:SharedPreferences通过键值对的方式存储数据,它的储存方式相对简单易用。


    实现原理:
    <1>存储数据:通过Context类所提供的getSharedPreferences方法获取SharedPreferences对象:

    public SharedPreferences getSharedPreferences(String name, int mode)
    方法getSharedPreferences传入的第一个参数是文件名,如果文件不存在则会自动创建一个,默认的储存路径是:data/data/<package name>/shared_prefs/下,第二个参数是指定操作模式:MODE_PRIVATE(表示只有当前应用程序可以对sharedPreferences文件读写)、MODE_MULTI_PROCESS(用于会有多个进程中对同一个sharedPreferences文件读取)。

    获取到SharedPreferences对象后,通过SharedPreferences类所提供的方法edit获取Editor对象,由所获取的Editor对象中的相应方法存储所要保存的数据,如:

    putInt(String key, int value);
    putString(String key, String value);
    putLong(String key, long value);
    putFloat(String key, float value);
    

    Editor对象中的方法所传入的第一个参数是键值,第二个参数是所要保存的值。

    <2>读取数据:通过Context类所提供的getSharedPreferences方法获取SharedPreferences对象:

    public SharedPreferences getSharedPreferences(String name, int mode)
    方法getSharedPreferences传入的第一个参数是文件名,第二个参数是指定操作模式:MODE_PRIVATE(表示只有当前应用程序可以对sharedPreferences文件读写)、MODE_MULTI_PROCESS(用于会有多个进程中对同一个sharedPreferences文件读取)。

    获取到SharedPreferences对象后,通过SharedPreferences类所提供的相应方法获取所要的数据,如:

    int getInt(String key, int defValue);
    String getString(String key, String defValue);
    long getLong(String key, long defValue);
    float getFloat(String key, float defValue);

    SharedPreferences类所提供的获取数据的方法中所传入的第一个参数是所要获取的数据对应的键值,第二个参数是默认的值。

    对于SharedPreferences存储的方式,这里提供了一个工具类以方便使用:

    import java.util.Map;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;
    
    /**
     * @description SharedPreferences 工具类
     */
    public class SharedPreferencesUtil {
    	// 所要保存数据的文件名
    	public static String FILLNAME = "save";
    
    	/**
    	 * 存入某个key对应的value值
    	 * 
    	 * @param context
    	 * @param key
    	 * @param value
    	 */
    	public static void put(Context context, String key, Object value) {
    		put(context, key, value, FILLNAME, Context.MODE_PRIVATE);
    	}
    
    	public static void put(Context context, String key, Object value,
    			String fileName) {
    		put(context, key, value, fileName, Context.MODE_PRIVATE);
    	}
    
    	public static void put(Context context, String key, Object value, int mode) {
    		put(context, key, value, FILLNAME, mode);
    	}
    
    	public static void put(Context context, String key, Object value,
    			String fileName, int mode) {
    		SharedPreferences sp = context.getSharedPreferences(fileName, mode);
    		Editor editor = sp.edit();
    		if (value instanceof String) {
    			editor.putString(key, (String) value);
    		} else if (value instanceof Integer) {
    			editor.putInt(key, (Integer) value);
    		} else if (value instanceof Boolean) {
    			editor.putBoolean(key, (Boolean) value);
    		} else if (value instanceof Float) {
    			editor.putFloat(key, (Float) value);
    		} else if (value instanceof Long) {
    			editor.putLong(key, (Long) value);
    		}
    		editor.apply();
    		// editor.commit(); 同步效率低
    	}
    
    	/**
    	 * 得到某个key对应的值
    	 * 
    	 * @param context
    	 * @param key
    	 * @param defValue
    	 * @return
    	 */
    
    	public static Object get(Context context, String key, Object defValue) {
    		return get(context, key, defValue, FILLNAME, Context.MODE_PRIVATE);
    	}
    
    	public static Object get(Context context, String key, Object defValue,
    			String fileName) {
    		return get(context, key, defValue, fileName, Context.MODE_PRIVATE);
    	}
    
    	public static Object get(Context context, String key, Object defValue,
    			int mode) {
    		return get(context, key, defValue, FILLNAME, mode);
    	}
    
    	public static Object get(Context context, String key, Object defValue,
    			String fileName, int mode) {
    		SharedPreferences sp = context.getSharedPreferences(fileName, mode);
    		if (defValue instanceof String) {
    			return sp.getString(key, (String) defValue);
    		} else if (defValue instanceof Integer) {
    			return sp.getInt(key, (Integer) defValue);
    		} else if (defValue instanceof Boolean) {
    			return sp.getBoolean(key, (Boolean) defValue);
    		} else if (defValue instanceof Float) {
    			return sp.getFloat(key, (Float) defValue);
    		} else if (defValue instanceof Long) {
    			return sp.getLong(key, (Long) defValue);
    		}
    		return null;
    	}
    
    	/**
    	 * 返回所有数据
    	 * 
    	 * @param context
    	 * @return
    	 */
    	public static Map<String, ?> getAll(Context context) {
    		return getAll(context, FILLNAME, Context.MODE_PRIVATE);
    	}
    
    	public static Map<String, ?> getAll(Context context, String fileName) {
    		return getAll(context, fileName, Context.MODE_PRIVATE);
    	}
    
    	public static Map<String, ?> getAll(Context context, String fileName,
    			int mode) {
    		SharedPreferences sp = context.getSharedPreferences(fileName, mode);
    		return sp.getAll();
    	}
    
    	/**
    	 * 移除某个key值已经对应的值
    	 * 
    	 * @param context
    	 * @param key
    	 */
    	public static void remove(Context context, String key) {
    		remove(context, key, FILLNAME, Context.MODE_PRIVATE);
    	}
    
    	public static void remove(Context context, String key, String fileName) {
    		remove(context, key, fileName, Context.MODE_PRIVATE);
    	}
    
    	public static void remove(Context context, String key, String fileName,
    			int mode) {
    		SharedPreferences sp = context.getSharedPreferences(fileName, mode);
    		Editor editor = sp.edit();
    		editor.remove(key);
    		editor.apply();
    		// editor.commit(); 同步效率低
    	}
    
    	/**
    	 * 清除所有内容
    	 * 
    	 * @param context
    	 */
    	public static void clear(Context context) {
    		clear(context, FILLNAME, Context.MODE_PRIVATE);
    	}
    
    	public static void clear(Context context, String fileName) {
    		clear(context, fileName, Context.MODE_PRIVATE);
    	}
    
    	public static void clear(Context context, String fileName, int mode) {
    		SharedPreferences sp = context.getSharedPreferences(fileName, mode);
    		Editor editor = sp.edit();
    		editor.clear();
    		editor.apply();
    	}
    }



    3、数据库存储

    方式:其实在安卓系统中内置了SQLite数据库,它是一个轻量级的关系型数据库,运算速度快,占用资源少,很适合在移动设备上使用,不仅支持标准SQL语法,还遵循ACID(数据库事务)原则,使用起来非常方便!

    使用场景:在上面两种实现数据持久化方式中,都是存储一些简单的数据,当我们开发中需要储存大量复杂的关系型数据的时候,例如保存客户信息、联系人信息等,前两种方式就胜任不了了,这个时候我们就可以使用安卓内置的数据库。


    实现原理:

    <1>创建数据库:在数据库的创建中,安卓给我们提供了SQLiteOpenHelper的两个方法,onCreate( )与onUpgrade( )来实现:

    onCreate(database):首次运行自定义继承SQLiteOpenHelper的类时生成数据库表
    onUpgrade(database,oldVersion,newVersion):在数据库的版本发生变化时会被调用, 一般在软件升级时才需改变版本号。
    
    步骤:
    Step 1:自定义一个类继承SQLiteOpenHelper类
    Step 2:在该类的构造方法的super中设置好要创建的数据库名,版本号
    Step 3:重写onCreate( )方法创建表结构
    Step 4:重写onUpgrade( )方法定义版本号发生改变后执行的操作
    
    代码:

    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class StudentSQLiteOpenHelper extends SQLiteOpenHelper {
    
        private static final String DATABASE_NAME = "student";
        private static final int DATABASE_VERSION = 1;
        public static final String TABLE_NAME = "table_student";
        private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ";
    
        private final String ID = "id";
        private final String NAME = "name";
        private final String SEX = "sex";
        private final String AGE = "age";
        
        private static StudentSQLiteOpenHelper instance = null;
        public static StudentSQLiteOpenHelper getInstance(Context context) {
            if(instance == null){
                synchronized (StudentSQLiteOpenHelper.class) {
                    if(instance == null)
                        instance = new StudentSQLiteOpenHelper(context);
                }
            }
            return instance;
        }
    
        public StudentSQLiteOpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
    
        // 数据库第一次创建时被调用
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_TABLE + TABLE_NAME + "(" 
                    + ID + " INTEGER PRIMARY KEY AUTOINCREMENT," 
                    + NAME + " VARCHAR(20)," 
                    + SEX + " VARCHAR(10)," 
                    + AGE + " INTEGER"
                    + ");");
        }
    
        // 软件版本号发生改变时调用
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
        }
    }
    在第一次运行自定义继承SQLiteOpenHelper的类时,会创建这个student.db的文件,并且会执行onCreate()里的方法,创建一个Student的表,Student表中包含四个字段:主键id、姓名name、性别sex和年龄age;接着如果修改db的版本号,那么下次启动就会调用onUpgrade()里的方法,注:如果是插入一个字段,则表中数据不会丢失,如果是重建表的话,表中的数据会全部丢失!



    <2>对数据库进行增、删、改、查操作

    ------------------------------------------------------------<增>----------------------------------------------------------------

    以上面创建的Student表为例,往表中添加数据可以通过SQLiteDatabase类所提供的insert方法:

    public long insert(String table, String nullColumnHack, ContentValues values)
    方法 insert中传入的第一个参数是数据所要添加的表,第二个参数是当values没有值的时候默认添加到表中的数据,第三个参数是所要添加的数据以HashMap<String,Object>型式保存。

    	public void addDataToDB(String name, String sex, int age) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			ContentValues values = new ContentValues();
    			values.put(NAME, name);
    			values.put(SEX, sex);
    			values.put(AGE, age);
    			db.insert(TABLE_NAME, null, values);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}


    ------------------------------------------------------------<删>----------------------------------------------------------------

    以上面创建的Student表为例,往表中添加数据可以通过SQLiteDatabase类所提供的delete方法:

    public int delete(String table, String whereClause, String[] whereArgs)

    方法delete中传入的第一个参数是要删除的数据所在的表,第二个参数是根据表中的字段作为删除依据,第三个参数是第二个参数对应的所要删除的数据。

    	public void deleteDataById(int id) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			db.delete(TABLE_NAME, ID + " = ? ", new String[] { String.valueOf(id) });// 根据id删除数据
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}

    上面所给出的代码是根据id进行数据删除,同时也可以精确到某条数据进行删除:

    	public void deleteData(String name, String sex, int age) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			db.delete(TABLE_NAME, NAME + " =? and " + SEX + " =? and " 
    					+ AGE + " =? ", new String[] { name, sex, String.valueOf(age) });// 精确到某条数据进行删除
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}
     

    ------------------------------------------------------------<改>----------------------------------------------------------------

    以上面创建的Student表为例,往表中添加数据可以通过SQLiteDatabase类所提供的update方法:

    public int update(String table, ContentValues values, String whereClause, String[] whereArgs)
    方法 update 中传入的第一个参数是要更新的数据所在的表名,第二个参数是新的数据,第三个参数是要更新数据的查找条件,第四个参数是条件的参数。

    	public void updateDataToDB(int id, String name, String sex, int age) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			ContentValues values = new ContentValues();
    			values.put(NAME, name);
    			values.put(SEX, sex);
    			values.put(AGE, age);
    			db.update(TABLE_NAME, values, ID + " =? ", new String[] { String.valueOf(id) });
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}


    ------------------------------------------------------------<查>----------------------------------------------------------------

    以上面创建的Student表为例,往表中添加数据可以通过SQLiteDatabase类所提供的query方法:

    public Cursor query(String table, String[] columns, String selection,
                String[] selectionArgs, String groupBy, String having,
                String orderBy)
    方法 update 中传入的参数依次是:表名、列名、where约束条件、where中占位符提供具体的值、指定group by的列、进一步约束、指定查询结果的排序方式。
    /**
     * 
     * Student类
     *
     **/
    public class StudentInfo {
    
    	private String name;
    	private String sex;
    	private int age;
    	
    	public StudentInfo(){
    		
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getSex() {
    		return sex;
    	}
    
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    }
    	public List<StudentInfo> queryData(){
    		List<StudentInfo> list = new ArrayList<StudentInfo>();
    		SQLiteDatabase db = getReadableDatabase();
    		try {
    			Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
    			if(cursor != null){
    				if(cursor.moveToFirst()){
    					do {
    						StudentInfo studentInfo = new StudentInfo();
    						studentInfo.setName(cursor.getString(cursor.getColumnIndex(NAME)));
    						studentInfo.setSex(cursor.getString(cursor.getColumnIndex(SEX)));
    						studentInfo.setAge(cursor.getInt(cursor.getColumnIndex(AGE)));
    						list.add(studentInfo);
    					} while (cursor.moveToNext());
    				}
    				cursor.close();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally{
    			db.close();
    		}
    		return list;
    	}

    对于以上对数据库的增、删、改、查的操作,提供StudentSQLiteOpenHelper类作为参考:

    import java.util.ArrayList;
    import java.util.List;
    
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.transition.ArcMotion;
    
    /**
     * 
     * 自定义继承SQLiteOpenHelper的类StudentSQLiteOpenHelper
     * 数据库的增、删、改、查操作
     *
     **/
    public class StudentSQLiteOpenHelper extends SQLiteOpenHelper {
    
    	private static final String DATABASE_NAME = "student";
    	private static final int DATABASE_VERSION = 1;
    	public static final String TABLE_NAME = "table_student";
    	private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ";
    
    	private final String ID = "id";
    	private final String NAME = "name";
    	private final String SEX = "sex";
    	private final String AGE = "age";
    	
    	private static StudentSQLiteOpenHelper instance = null;
    	public static StudentSQLiteOpenHelper getInstance(Context context) {
    		if(instance == null){
    			synchronized (StudentSQLiteOpenHelper.class) {
    				if(instance == null)
    					instance = new StudentSQLiteOpenHelper(context);
    			}
    		}
    		return instance;
    	}
    
    	public StudentSQLiteOpenHelper(Context context) {
    		super(context, DATABASE_NAME, null, DATABASE_VERSION);
    	}
    
    	// 数据库第一次创建时被调用
    	@Override
    	public void onCreate(SQLiteDatabase db) {
    		db.execSQL(CREATE_TABLE + TABLE_NAME + "(" 
    				+ ID + " INTEGER PRIMARY KEY AUTOINCREMENT," 
    				+ NAME + " VARCHAR(20)," 
    				+ SEX + " VARCHAR(10)," 
    				+ AGE + " INTEGER"
    				+ ");");
    	}
    
    	// 软件版本号发生改变时调用
    	@Override
    	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
    	}
    
    	public void add(String name, String sex, int age) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			ContentValues values = new ContentValues();
    			values.put(NAME, name);
    			values.put(SEX, sex);
    			values.put(AGE, age);
    			db.insert(TABLE_NAME, null, values);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}
    
    	public void delete(int id) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			db.delete(TABLE_NAME, ID + " = ? ",
    					new String[] { String.valueOf(id) });// 根据id删除数据
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}
    
    	public void delete(String name, String sex, int age) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			db.delete(TABLE_NAME, NAME + " =? and " + SEX + " =? and " + AGE
    					+ " =? ", new String[] { name, sex, String.valueOf(age) });// 精确到某条数据进行删除
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}
    
    	public void updateData(int id, String name, String sex, int age) {
    		SQLiteDatabase db = getWritableDatabase();
    		try {
    			ContentValues values = new ContentValues();
    			values.put(NAME, name);
    			values.put(SEX, sex);
    			values.put(AGE, age);
    			db.update(TABLE_NAME, values, ID + " =? ", new String[] { String.valueOf(id) });
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			db.close();
    		}
    	}
    	
    	public List<StudentInfo> queryData(){
    		List<StudentInfo> list = new ArrayList<StudentInfo>();
    		SQLiteDatabase db = getReadableDatabase();
    		try {
    			Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
    			if(cursor != null){
    				if(cursor.moveToFirst()){
    					do {
    						StudentInfo studentInfo = new StudentInfo();
    						studentInfo.setName(cursor.getString(cursor.getColumnIndex(NAME)));
    						studentInfo.setSex(cursor.getString(cursor.getColumnIndex(SEX)));
    						studentInfo.setAge(cursor.getInt(cursor.getColumnIndex(AGE)));
    						list.add(studentInfo);
    					} while (cursor.moveToNext());
    				}
    				cursor.close();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally{
    			db.close();
    		}
    		return list;
    	}
    }

    注:在对SQLiteDatabase和Cursor对象使用过程中,使用完后一定要记得调用close方法将其关闭,否则将会造成内存泄露。

    展开全文
  • 作为 Android数据存储方式之一的SharedPreferences(以下简称SP),我们在开发中也是或多或少会用到。今天就来总结一下如何使用 SP 以及使用 SP 的注意事项。 1.首先先聊聊使用SP 的注意事项 SP 适合存储一些轻...
  • Android数据存储与持久

    千次阅读 2016-09-29 23:00:43
    一、持久化技术简介瞬时数据是指那些存储在内存当中,有...这就需要用到数据持久化技术了数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。保存在内
  • 官方方案对比SharedPreference简称SP,使用键值对的形式保存原始类型的数据,默认以XML格式的文件来存储这些数据适用场景:存储量小、简单的数据优缺点:有自己的内存级的缓存,在数据量小的时候读取较快,但是跨...
  • 效果演示:其实我们在社交网络上面所发出的任何信息, 都希望能够保留下来....持久化技术则是提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换, Android系统中主要提供了3种方式用于简单地实现数据持久化...
  • Android数据持久化技术

    2021-01-25 21:40:18
    Android 数据持久化技术数据持久化文件存储从文件中读取数据SharedPreferences插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何...
  • Android保存Activity销毁而丢失的数据

    千次阅读 2017-01-12 21:26:35
    活动存在四种状态,分别是 运行状态、暂停状态、停止状态和销毁状态,除了运行状态之外,当系统内存不足的情况下,其他三种状态都有可能被回收,这样就会出现数据丢失的情况,那么如何在活动被回收之前保存数据呢,...
  • 数据持久化是开发过程中不可避免的,因为数据是核心,是非常重要的。 总结一下常用的数据持久化的方式:SharedPreferences存储数据、文件存储数据、SQLite数据库存储数据、ContentProvider存储数据... ...
  • 本文实例讲述了Android数据持久化之I/O操作。分享给大家供大家参考,具体如下:前面文章里我们简单的介绍了File的操作,这一节来说说使用android平台自带对象实现文件的基本操作主要的两个类:openFileOutput(写)和...
  • 最近利用下班时间,找了看什么书比较适合初学android的朋友,很多人推荐了这本书,于是就买了一本,感觉看书,... 上一篇主要介绍了本地文件实现数据持久化,那么这一篇就来介绍一个更加简单有效的实现数据持久化...
  • 安卓的四种存储数据的方式为: 1、SharedPreferences 2、文件存储(内部+外部):通过IO流读取文件 3、Sqlite 4、跨应用数据共享ContentProvide 一、SharedPreferences:最简单的 会将数据以xml文件的形式存储 存储...
  • 1、sharedpreference 共享参数(一般用于保存用户设置偏好); ** * 特点: * (1)以键值对的形式保存到data/data/应用程序包名/shared_prefs目录的XXX.xml文件中 * (2)目前支持的数据类型有String int ...
  • Android持久化技术

    2021-05-28 02:12:03
    1、文件存储2、SharedPreferences存储3、数据库的存储1、文件存储文件存储是Android中最基本的持久化方式,它不对存储的内容进行任何格式化处理,会原封不动的存储到文件中,所以这种方式适合存储简单的文本数据或二...
  • 安卓数据持久化工具类总结

    千次阅读 2015-03-05 08:34:58
    程序猿是最懒的生物,开发中从不重复造轮子,实际开发中数据吃就化是必然要处理的一个问题,先总结了几个除处理sqlite外的几个工具类,因为sqlite可以直接用orm,持久数据有I/O,SharedPreference等等方式。...
  • 数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据时处于持久状态的,持久化技术...
  • 案例界面: 实现代码: ...主界面activity_main实现代码: ...<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=... android:id="@+id/activit
  • Android系统中主要提供了三种方式用于简单的实现数据持久化功能: 文件存储(手机自带的内存)、SharedPreferences存储以及数据库存储, 当然还可以用sd卡存储 1,文件存储 特点:手机自带的内存,只能供当前...
  • SharedPreferences作为Android数据存储方式的一种,我们经常会用到,它适合用来保存那些少量的数据,特别是键值对数据,比如配置信息,登录信息等。不过要想做到正确使用SharedPreferences,就需要弄清楚下面几个...
  • 一、保存文件到手机内存/*** 保存数据到手机rom的文件里面.* @param context 应用程序的上下文 提供环境* @param name 用户名* @param password 密码* @throws Exception*/public static void saveToRom(Context ...
  • Android数据持久化存储共有四种方式,分别是文件存储、SharedPreferences、Sqlite数据库和ContentProvider。在本篇幅中只介绍前面三种存储方式,因为ContentProvider属于android四大组件之一,所以它的数据存储方式...
  • Android系统主要提供三种实现数据持久化功能的方法: 1、文件存储 2、SharedPreference存储 3、数据库存储 你还可以存储在手机的SD卡内,不过上面三个方法比较安全。文件存储向文件中写入数据Context类提供了一个...
  • android 使用SharedPreferences保存list数据

    千次阅读 2015-08-14 10:18:37
    SharedPreferences sp = context.getSharedPreferences("listname", Context.MODE_PRIVATE); String result = sp.getString(key, ""); try { JSONArray array = new JSONArray(result); for (int i =...
  • GitHub项目地址: ...也就是说,当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。而且SharePreferences还支持多种不同的数据类型存...
  • Android中我们经常需要持久保存数据,这时可以使用文件,SharePreference,以及SQLite等。如果我想保存一个对象呢?有些人会立马想到用orm框架,但是我可能不想依赖这个框架。实际上如果数据量不大,用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,696
精华内容 678
关键字:

安卓数据持久sp的保存数据的特点