ArrayMap存2000条数据是否不足?Android加载JSON停滞求助
问题分析与解决方案:加载大JSON文件时应用停滞
首先明确:ArrayMap的容量绝对不是导致停滞的原因,ArrayMap会自动扩容,存储2000条数据完全没有压力。你的应用停滞是因为在UI线程做了大量耗时操作,具体看下面的拆解:
核心问题所在
你在onPostExecute的循环里,每次都执行这样的代码:
textViewProg.setText(textViewProg.getText()+"key : "+ ArrayDati.get(i).Key +"\n"+textViewProg.getText()+"name : "+ ArrayDati.get(i).Name +"\n"+textViewProg.getText()+"code : "+ ArrayDati.get(i).Code );
这里有两个致命问题:
- 重复拼接字符串的低效操作:每次循环都要读取当前TextView的文本,再拼接新内容,2000次循环会产生大量临时字符串对象,既耗内存又费时间。
- 频繁触发UI重绘:每次调用
setText都会让TextView重新渲染界面,2000次重复渲染直接阻塞UI线程,导致应用看起来停滞无响应。
修复步骤
1. 把数据解析移到后台线程(优化性能)
虽然你用了AsyncTask,但之前把JSON解析放在了UI线程的onPostExecute里,其实可以直接在doInBackground里完成解析和数据存储,让UI线程只负责最后一次更新:
// 修改AsyncTask的泛型,返回处理好的ArrayMap private class JsonCLASS extends AsyncTask<String, Void, ArrayMap<Integer, Valori>> { @Override protected void onPreExecute() { super.onPreExecute(); caric = new ProgressDialog(MainActivity.this); caric.setMessage("Please wait"); caric.setCancelable(false); caric.show(); } @Override protected ArrayMap<Integer, Valori> doInBackground(String... params) { HttpURLConnection connection = null; BufferedReader reader = null; ArrayMap<Integer, Valori> tempArray = new ArrayMap<>(); try { URL url = new URL(params[0]); connection = (HttpURLConnection) url.openConnection(); connection.connect(); InputStream stream = connection.getInputStream(); reader = new BufferedReader(new InputStreamReader(stream)); StringBuffer buffer = new StringBuffer(); String line = ""; while ((line = reader.readLine()) != null) { buffer.append(line); Log.d("Response: ", "> " + line); } // 在这里完成JSON解析,避免占用UI线程 JSONObject jsonObject = new JSONObject(buffer.toString()); JSONArray Arr = jsonObject.getJSONArray("clubs"); for (int i = 0; i < Arr.length(); i++){ JSONObject jsonPart = Arr.getJSONObject(i); tempArray.put(i,new Valori( jsonPart.getString("key"), jsonPart.getString("name"), jsonPart.getString("code"))); } return tempArray; } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } try { if (reader != null) { reader.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; }
2. 优化UI更新逻辑,一次性渲染内容
在onPostExecute里,用StringBuilder高效拼接所有内容,最后只调用一次setText,避免频繁触发UI重绘:
@Override protected void onPostExecute(ArrayMap<Integer, Valori> result) { super.onPostExecute(result); if (result == null) { textViewProg.setText("加载失败"); caric.dismiss(); return; } ArrayDati = result; StringBuilder sb = new StringBuilder(); // 一次性拼接所有内容 for (int i = 0; i < result.size(); i++){ Valori val = result.get(i); sb.append("key : ").append(val.Key).append("\n"); sb.append("name : ").append(val.Name).append("\n"); sb.append("code : ").append(val.Code).append("\n\n"); } // 只调用一次setText更新UI textViewProg.setText(sb.toString()); if (caric.isShowing()) { caric.dismiss(); } } }
3. 额外建议:替换废弃的AsyncTask
AsyncTask在Android 11之后已被标记为废弃,推荐用Coroutines(协程)替代,代码更简洁且线程切换更灵活:
// 在onCreate中设置按钮点击事件 buttonProg.setOnClickListener(v -> { caric = ProgressDialog.show(MainActivity.this, "", "Please wait", false, false); // 开启IO线程处理网络请求和解析 CoroutineScope(Dispatchers.IO).launch { try { URL url = new URL("https://raw.githubusercontent.com/openfootball/football.json/master/2015-16/en.1.clubs.json"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.connect(); InputStream stream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuffer buffer = new StringBuffer(); String line = ""; while ((line = reader.readLine()) != null) { buffer.append(line); } JSONObject jsonObject = new JSONObject(buffer.toString()); JSONArray Arr = jsonObject.getJSONArray("clubs"); ArrayMap<Integer, Valori> tempArray = new ArrayMap<>(); for (int i = 0; i < Arr.length(); i++){ JSONObject jsonPart = Arr.getJSONObject(i); tempArray.put(i,new Valori( jsonPart.getString("key"), jsonPart.getString("name"), jsonPart.getString("code"))); } // 切换到主线程更新UI withContext(Dispatchers.Main){ ArrayDati = tempArray; StringBuilder sb = new StringBuilder(); for (int i = 0; i < tempArray.size(); i++){ Valori val = tempArray.get(i); sb.append("key : ").append(val.Key).append("\n"); sb.append("name : ").append(val.Name).append("\n"); sb.append("code : ").append(val.Code).append("\n\n"); } textViewProg.setText(sb.toString()); caric.dismiss(); } } catch (Exception e) { e.printStackTrace(); withContext(Dispatchers.Main){ textViewProg.setText("加载失败"); caric.dismiss(); } } } });
总结
你的问题和ArrayMap容量无关,核心是UI线程中频繁的字符串拼接和UI重绘导致阻塞。通过把数据解析移到后台线程,用StringBuilder一次性拼接内容再更新UI,就能彻底解决应用停滞的问题。
内容的提问来源于stack exchange,提问作者user11056327
相关产品推荐
相关产品推荐

