Java 如何解析大型JSON文件以获得搜索栏建议

Java 如何解析大型JSON文件以获得搜索栏建议,java,android,json,Java,Android,Json,我正在尝试解析一个29mb的天气应用程序,其中包含世界上的城市 这是JSON结构: [ { "id": 707860, "name": "Hurzuf", "country": "UA", "coord": { "lon": 34.283333, "lat": 44.549999 } }, { "id": 519188, "name": "Novinki", "country": "RU",

我正在尝试解析一个29mb的天气应用程序,其中包含世界上的城市

这是JSON结构:

[
  {
    "id": 707860,
    "name": "Hurzuf",
    "country": "UA",
    "coord": {
      "lon": 34.283333,
      "lat": 44.549999
    }
  },
  {
    "id": 519188,
    "name": "Novinki",
    "country": "RU",
    "coord": {
      "lon": 37.666668,
      "lat": 55.683334
    }
  },
  {
    "id": 1283378,
    "name": "Gorkhā",
    "country": "NP",
    "coord": {
      "lon": 84.633331,
      "lat": 28
    }
  },
...
]
我有一个片段,其中包含保存的城市列表和一个fab,该fab提示一个带有文本字段的警报对话框,用户应该在其中键入城市名称并从解析的数据中获取建议

我的问题是,解析这个文件会消耗大量内存并减慢用户xp的速度(即使它运行在不同的线程上,但在操作完成之前,fab将被禁用)。 每次用户访问cities片段时解析文件似乎很愚蠢,因此将结果对象保留在内存中, 所以我想我的问题是我应该如何处理这个问题

使用类似GSON的线程或文章是很好的,但它不能解决问题的重复性

public静态列表getCitiesFromJSON(上下文){
List cityList=new LinkedList();
试一试{
InputStream=context.getAssets().open(“jsons/city.list.min.json”);
JsonReader=新的JsonReader(新的InputStreamReader(即“UTF-8”);
reader.beginArray();
Gson Gson=new GsonBuilder().create();
while(reader.hasNext()){
City cityJson=gson.fromJson(reader,City.class);
城市=新城();
setId(cityJson.getId());
city.setName(cityJson.getName());
city.setCountry(cityJson.getCountry());
city.setCoord(新的Coord(cityJson.getCoord().getLon(),cityJson.getCoord().getLat());
城市列表。添加(城市);
}
reader.close();
}捕获(不支持的编码异常e){
e、 printStackTrace();
}捕获(IOE异常){
e、 printStackTrace();
}
返回城市列表;
}
tl;dr


每次用户尝试添加到列表时,都需要解析大JSON以获得搜索建议,但该操作既占用内存又耗时,因此我需要一种更好的方法。

我认为在您的情况下,在内存中加载城市(Singleton对象)更好, 或者,如果目标客户机资源/ram将受到影响,那么您需要一个远程服务器来完成这项工作,或者是一个搜索引擎(如ElasticSearch)或者一个rest应用程序来完成处理和缓存


另外,缓存搜索请求将有助于防止冗余处理

我认为在你的例子中,加载内存中的城市(Singleton对象)更好, 或者,如果目标客户机资源/ram将受到影响,那么您需要一个远程服务器来完成这项工作,或者是一个搜索引擎(如ElasticSearch)或者一个rest应用程序来完成处理和缓存


另外,缓存搜索请求将有助于防止冗余处理

方法1:更好的方法是在应用程序启动后在后台请求JSON,并将其保存到本地存储(SQlite、Room Persistence或SharedReference)

方法2:第二个技巧是只显示足够大的数字,而不是太大。 假设用户有1000个结果与用户输入字符串匹配。只需查询本地或远程数据库以显示最佳匹配的100。任何神智正常的人都不会在不再次修改/写入输入文本的情况下滚动100个结果


最佳方法:使用分页库在用户向下滚动时加载数据。

方法1:更好的方法是在应用程序启动后立即在后台请求JSON,并将其保存到本地存储(SQlite、Room Persistence或SharedReference)

方法2:第二个技巧是只显示足够大的数字,而不是太大。 假设用户有1000个结果与用户输入字符串匹配。只需查询本地或远程数据库以显示最佳匹配的100。任何神智正常的人都不会在不再次修改/写入输入文本的情况下滚动100个结果


最佳方法:当用户向下滚动时,使用分页库加载数据。

以下是我解决此问题的方法:

  • 用于处理数据库操作的文件室:
城市实体:

@实体
公营城市{
@主键
私人长id;
私有字符串名称;
私人国家;
@嵌入
私人合作社;
公共城市(){
}
公共城市(JSONObject json){
this.id=json.optLong(“id”);
this.name=json.optString(“name”);
this.country=json.optString(“国家”);
this.coord=new-coord(json.optJSONObject(“coord”));
}
公共城市(长id、字符串名称、字符串国家/地区、坐标){
this.id=id;
this.name=名称;
这个国家=国家;
this.coord=coord;
}
//接球手和接球手。。。
}
城市道:


@刀
公共界面城市大道{
@查询(“选择*来自城市”)
List getAll();
//用于查询搜索建议
@查询(“从城市中选择*名称,如:名称| |'%”按名称排序ASC限制10”)
城市findByName(字符串名称);
//用于确定是否创建了数据库
@查询(“从城市中选择计数(*))
int getCitySize();
@插入
void insertAll(城市…城市);
@插入
无效插入(城市);
@删除
无效城市(城市);
@查询(“从城市删除”)
公共无效核城市();
}
应用数据库:

@数据库(实体={City.class},版本=1)
公共抽象类AppDatabase扩展了RoomDatabase{
公共摘要CityDao CityDao();
}
  • 在应用程序类中,我使用回调实现了一个Runnable,该回调在解析JSON并填充db时开始倒计时闩锁的倒计时(由AddCityFragment用于启用fab)
应用程序:

公共类应用程序扩展