Android应用JSON文件解析与存储优化方案求助
Android JSON文件批量解析与缓存优化方案
一、替换SharedPreferences,改用高效存储方案
SharedPreferences是键值对存储,批量写入大量JSON字符串会产生严重的性能瓶颈,建议替换为以下方案:
- Room数据库:基于SQLite的封装,适合结构化数据的批量存储与查询,读写效率远高于SP。将
CallRegistration定义为Room实体类,通过批量插入、单条查询替代SP的逐个键值操作。 - 二进制文件缓存:将解析后的
CallLogItem列表通过序列化(如Parcelable、Protobuf)写入单个缓存文件,相比JSON字符串+SP的组合,二进制读写速度更快、占用空间更小。
二、解析流程优化
- 并行解析:用线程池(如
Executors.newFixedThreadPool)并行处理多个JSON文件的解析任务,利用多核CPU减少总耗时(注意文件IO的线程安全,避免同时操作同一文件)。 - 替换JSON解析库:将Gson替换为Moshi或Jackson,二者在解析速度和内存占用上更优,尤其是Moshi对Kotlin的支持更友好,能显著提升解析效率。
- 智能缓存校验:遍历文件时记录每个文件的最后修改时间,仅当文件更新时才重新解析,避免无效的缓存读取判断。同时提前通过文件名后缀过滤非JSON文件,减少无效操作。
三、加载逻辑优化
- 改用协程替代Loader:Android Loader的灵活性不足,改用
ViewModel+协程(viewModelScope.launch(Dispatchers.IO))处理后台解析任务,更精细地控制任务生命周期与进度。 - 分页加载:若RecyclerView无需一次性展示所有数据,采用分页加载策略,启动时仅加载前N条数据,滑动到底部再加载下一批,大幅降低启动耗时。
四、Room方案代码示例
1. 定义Room实体类
@Entity(tableName = "call_registrations") public class CallRegistration { @PrimaryKey private String fileId; // 用文件URI或唯一标识作为主键 private long lastModified; // 文件最后修改时间,用于校验缓存有效性 // 自定义所需字段... // Getter & Setter }
2. 创建Dao接口
@Dao public interface CallRegistrationDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insertAll(List<CallRegistration> registrations); @Query("SELECT * FROM call_registrations WHERE fileId = :fileId") CallRegistration getByFileId(String fileId); }
3. 数据库实例类
@Database(entities = {CallRegistration.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract CallRegistrationDao callRegistrationDao(); private static volatile AppDatabase INSTANCE; public static AppDatabase getInstance(Context context) { if (INSTANCE == null) { synchronized (AppDatabase.class) { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "call_log_db") .build(); } } } return INSTANCE; } }
4. 改造Loader的解析逻辑
@Override public List<CallLogItem> loadInBackground() { AppDatabase db = AppDatabase.getInstance(getContext()); CallRegistrationDao dao = db.callRegistrationDao(); List<CallLogItem> allItems = new ArrayList<>(); List<CallRegistration> toCache = new ArrayList<>(); // 提前过滤出文件夹中的JSON文件 DocumentFile[] files = getTargetFolder().listFiles(file -> file.getName().endsWith(".json")); if (files == null) return allItems; for (DocumentFile file : files) { String fileId = file.getUri().toString(); long fileModifyTime = file.lastModified(); CallRegistration cached = dao.getByFileId(fileId); if (cached != null && cached.getLastModified() == fileModifyTime) { // 缓存有效,直接转换为CallLogItem allItems.add(convertToCallLogItem(cached)); } else { // 解析原文件 String jsonContent = readFileContent(file); CallLogItem[] items = new Moshi.Builder().build().adapter(CallLogItem[].class).fromJson(jsonContent); if (items != null) { Collections.addAll(allItems, items); // 生成新缓存对象 CallRegistration newCache = new CallRegistration(); newCache.setFileId(fileId); newCache.setLastModified(fileModifyTime); // 设置其他字段 toCache.add(newCache); } } } // 批量插入缓存 if (!toCache.isEmpty()) { dao.insertAll(toCache); } // 排序后返回 Collections.sort(allItems, (item1, item2) -> /* 自定义排序逻辑 */); return allItems; } // 读取文件内容工具方法 private String readFileContent(DocumentFile file) { StringBuilder content = new StringBuilder(); try (InputStream is = getContext().getContentResolver().openInputStream(file.getUri()); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { String line; while ((line = reader.readLine()) != null) { content.append(line); } } catch (IOException e) { e.printStackTrace(); } return content.toString(); }
内容的提问来源于stack exchange,提问作者user3298565
相关产品推荐
相关产品推荐

