- Android高效进阶:从数据到AI
- 胡强
- 2799字
- 2020-08-27 20:29:38
1.3 数据存储和上报
对于移动应用来说,数据日志存储库是必不可少的基础设施,数据日志模块作为底层的数据基础,对上层的性能影响必须尽量小,但是数据日志的写操作是非常高频的,频繁在Java堆里操作数据容易导致GC(垃圾回收)的发生,从而引起应用卡顿,频繁的I/O(输入/输出)操作也很容易导致CPU占用过高,甚至出现CPU峰值,影响应用的整体性能。
接下来会从数据加密方案、数据存储策略及数据上报策略等方面来进行介绍。
1.3.1 数据加密方案
移动端数据日志的安全性是至关重要的,绝对不能随意被破解,更不能明文存储,还要防止网络被劫持导致的日志泄露。
通常采用流式加密的方式,使用对称密钥加密数据日志,并存储到本地。同时在上传数据日志时,使用非对称密钥对对称密钥Key做加密上传,防止密钥Key被破解,从而在网络层保证日志上报安全。
如图1-4所示主要解决的是数据存储到本地和网络传输的安全问题,将密钥做成可配置下发,并且利用服务端做签名证书安全校验,数据存储的安全性问题即可得到解决。
图1-4
密钥的管理有如下一些需要注意的地方。
(1)密钥不能为常量,应随机、定期更换,如果加密数据时使用的密钥为常量,则相同明文加密会得到相同的密文,很难防止字典攻击。
(2)开发时要规避密钥硬编码。
在实际开发中,密钥如何保存始终是绕不过去的坎。因为硬编码在代码中容易被逆向破解,所以放在设备上的某个文件容易被有经验的破解者逆向找到。在这里推荐使用成熟、专业的安全服务公司的安全组件服务,其中的安全加密功能提供了开发者密钥的安全管理与加密算法实现,可以保证密钥的安全性,实现安全的加/解密操作。介绍完数据加密,接下来讲解数据存储策略。
1.3.2 数据存储策略
Android提供了多种选择来保存永久性的数据,根据不同的需求使用不同的保存方式。一般情况下,保存数据的方式有下面5种。
● SharedPreferences
● 内部存储
● 外部存储
● SQLite
● 网络连接
下面主要来看看这5种具体的数据保存方式。
1.SharedPreferences
SharedPreferences(以下简称SP)以键值对形式进行存储,数据以xml形式存储在/data/data/项目包名/shared_prefs/xml.xml中。一般来说,SP只能存储基本类型的数据,如布尔型、浮点型、整型及字符串。在默认的情况下,SP保存的文件是应用的私有文件,其他应用(和用户)不能访问这些文件。
SP不支持多进程间通信,多进程间使用这种方式可能会导致数据异常。
2.内部存储
直接在设备的内部存储中保存文件。在默认的情况下,保存到内部存储的文件是应用的私有文件,其他应用(和用户)不能访问这些文件。当用户卸载应用时,这些文件也会被移除。
1. String FILENAME = "hello_file.txt"; 2. String string = "hello world!"; 3. 4. FileOutputStream fos = null; 5. try { 6. fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); 7. fos.write(string.getBytes()); 8. fos.close(); 9. } catch(FileNotFoundException e){ 10. e.printStackTrace(); 11. } catch(IOException e){ 12. e.printStackTrace(); 13. }
执行上面的代码后,在/data/data/项目包名/files/下可以看到已经成功地创建了相应的文件并且把数据写了进去。
存储文件操作的其他方法(都在Context类中)如下。
● getFilesDir(),获取存储内部文件的文件系统目录的绝对路径。返回路径为/data/data/com.xxx.xxx/files。
● getDir(),获取在内部存储空间创建的(或打开现有的)目录。如getDir("mq",Context. MODE_PRIVATE).getAbsolutePath(),返回结果为/data/data/com.xxx.xxx/ app_mq,可以看到系统自动在文件名前添加了“app_”。
● deleteFile(),删除保存在内部存储空间的文件。如deleteFile("mq")会删除*/data/data/com.xxx.xxx/files*目录中对应mq的文件;如果存在文件并删除成功,则返回true;反之,则返回false。
● fileList(),返回应用当前保存的一系列文件,即列出*/data/data/com.xxx.xxx/ files*目录下的所有文件。
3.外部存储
每个兼容Android的设备都支持可用于保存文件的共享“外部存储”。该外部存储可能是可移除的存储介质(如SD卡)或内部(不可移除)存储。保存到外部存储中的文件是全局可读取的文件,而且在计算机上启用USB大容量存储传输文件后,可由用户修改这些文件。外部存储方式分为两种,一种是在应用卸载后,存储数据会被删除;另一种是永久存储,即使应用被卸载,存储的数据依然存在。下面分别介绍这两种存储方式。
(1)通过context.getExternalFilesDir(null).getPath()获得路径,得到的路径是*/storage/emulated/0/ Android/data/package_name/*,在应用卸载后,存储的数据会被删除。
如果处理的文件不适合其他应用使用(例如,仅供自己应用使用的图形纹理或音效),则应该调用getExternalFilesDir()来使用外部存储上的私有存储目录。此方法还会采用type参数指定子目录的类型(如DIRECTORY_MOVIES)。
如果不需要特定的媒体目录,可以传递null以接收应用私有目录的根目录。从Android 4.4开始,读取或写入应用私有目录中的文件不再需要READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE权限。
因此,可以通过添加maxSdkVersion属性来声明,只能在较低版本的Android中请求该权限:
1. <manifest ...> 2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" 3. android:maxSdkVersion="18" /> 4. ... 5. </manifest>
注意:当用户卸载应用时,此目录及其内容将被删除。此外,系统媒体扫描程序不会读取这些目录中的文件,因此不能从MediaStore内容提供程序访问这些文件。同样,不应该将这些目录用于最终属于用户的媒体文件,例如,使用应用拍摄或编辑的照片或用户使用应用购买的音乐等文件应保存在公共目录中。
除context.getExternalFilesDir()外,还有getExternalCacheDir(),通过后者将文件保存到*/storage/emulated/0/Android/data/package_name/cache*目录下。当文件不再需要时,要记得把缓存文件删除。
(2)永久存储,即使应用被卸载,存储的数据依然存在,如存储路径/storage/emulated/0/mDiskCache,可以通过Environment.getExternalStorageDirectory().getAbsolutePath()+“/mDiskCache”来获取路径。
Android N和更高版本的应用无法按名称共享私有文件,尝试共享“file://”URI将会引发FileUriExposedException。如果应用需要与其他应用共享私有文件,则可以将FileProvider与FLAG_GRANT_READ_URI_PERMISSION配合使用。
4.数据库SQLite
Android提供了对SQLite数据库的完全支持。应用中的任何类(不包括应用外部的类)均可按名称访问所创建的任何数据库。关于SQLite的介绍、基本使用以及升级策略,这里不做更多展开。
5.网络连接
使用网络(如果可用)来存储和检索与自己的网络服务有关的数据。若要执行网络操作,请使用以下包中的类。
● java.net.*
● android.net.*
1.3.3 数据上报策略
数据上报策略主要从策略配置和相关接口设置来进行介绍。
1.Android数据上报策略配置(见表1-1)
表1-1
表1-1介绍了常用的数据上报策略配置,设置数据上报策略可以有效节省流量。可以使用以下3种方式调整App的数据上报策略。
(1)在App启动时指定上报策略(默认为APP_LAUNCH)。
StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT);
通常支持的上报策略为表1-1中的6种。
SDK默认在APP_LAUNCH+Wi-Fi下实时上报,对于响应要求比较高的应用,比如竞技类游戏,可关闭Wi-Fi实时上报,并选择APP_LAUNCH或PERIOD上报策略。
(2)考虑到Wi-Fi上报数据的代价比较低,为了更及时地获取用户数据,SDK默认在Wi-Fi网络下实时发送数据。可以调用下面的接口禁用此功能(在Wi-Fi条件下仍使用原定策略)。
void StatConfig.setEnableSmartReporting(boolean isEnable)
(3)通过在Web界面上配置,开发者可以在线更新上报策略,替换App内的原有策略,替换后的策略立即生效并存储在本地,App后续启动时会自动加载该策略。
上面3种方式的优先级顺序:Wi-Fi条件下智能实时发送>Web在线配置>本地默认。介绍完数据上报策略配置后,下面介绍相关的数据上报设置接口。
2.相关的数据上报设置接口
相关的数据上报设置接口如下。
(1)设置最大缓存未发送消息个数(默认值是1024)。
void StatConfig.setMaxStoreEventCount(int maxStoreEventCount)
当缓存消息的数量超过阈值时,最早的消息会被丢弃。
(2)(仅在发送策略为BATCH时有效)设置最大批量发送消息个数(默认值是30)。
void StatConfig.setMaxBatchReportCount(int maxBatchReportCount)
(3)(仅在发送策略为PERIOD时有效)设置间隔时间(默认值是24×60,即1天)。
void StatConfig.setSendPeriodMinutes(int minutes)
(4)开启SDK LogCat开关(默认值是false)。
void StatConfig.setDebugEnable(boolean debugEnable)