You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 09:05:27