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

加载大量本地JSON时应用卡顿,求AsyncTask改造方案(含进度)

解决加载大JSON时应用冻结的问题(AsyncTask实现+进度显示)

嘿,我来帮你搞定这个问题!你现在的代码直接在**主线程(UI线程)**里读取和解析10000+条数据的JSON文件,这肯定会阻塞UI更新——安卓主线程不能处理超过200ms的耗时操作,更别说40秒了,所以应用才会看起来“冻结”。

下面我给你把代码改成AsyncTask实现,还加上了进度百分比显示,这样用户能看到加载过程,应用也不会卡顿了:

第一步:准备UI布局(添加进度显示)

先在你的布局文件里加一个水平进度条和显示百分比的文本,用来展示加载进度:

<ProgressBar
    android:id="@+id/progressBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:progress="0"
    android:max="100"
    style="?android:attr/progressBarStyleHorizontal"/>

<TextView
    android:id="@+id/progressText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="0%"/>

第二步:定义数据模型类

先创建一个Item类来存储JSON里的对象数据,方便后续使用:

public class Item {
    private int id;
    private String name;

    public Item(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getter方法,方便获取数据
    public int getId() { return id; }
    public String getName() { return name; }
}

第三步:实现AsyncTask子类

这个类会把所有耗时的读取、解析操作放到后台线程,同时实时更新进度到UI:

public class LoadJsonTask extends AsyncTask<Void, Integer, List<Item>> {
    private Context mContext;
    private ProgressBar mProgressBar;
    private TextView mProgressText;
    private OnLoadCompleteListener mListener;

    // 回调接口:用来通知主线程加载完成/失败
    public interface OnLoadCompleteListener {
        void onLoadComplete(List<Item> items);
        void onLoadFailed(Exception e);
    }

    // 构造方法:传入需要的UI控件和回调
    public LoadJsonTask(Context context, ProgressBar progressBar, TextView progressText, OnLoadCompleteListener listener) {
        mContext = context;
        mProgressBar = progressBar;
        mProgressText = progressText;
        mListener = listener;
    }

    // 任务执行前:初始化进度条
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mProgressBar.setProgress(0);
        mProgressText.setText("0%");
    }

    // 后台线程执行:读取JSON、解析数据
    @Override
    protected List<Item> doInBackground(Void... voids) {
        List<Item> itemList = new ArrayList<>();
        try {
            InputStream inputStream = mContext.getAssets().open("LocalTest.json");
            long totalFileSize = inputStream.available();
            long readSize = 0;
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024]; // 用1024字节缓冲区高效读取
            int bytesRead;

            // 读取文件,实时计算进度
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                readSize += bytesRead;
                int readProgress = (int) ((readSize * 100) / totalFileSize);
                // 发布读取进度(占总进度的50%)
                publishProgress(readProgress / 2);
            }
            inputStream.close();
            String jsonString = outputStream.toString("UTF-8");
            outputStream.close();

            // 解析JSON数组,实时计算解析进度
            JSONObject jsonObject = new JSONObject(jsonString);
            JSONArray resultArray = jsonObject.getJSONArray("result");
            int totalItems = resultArray.length();

            for (int x = 0; x < totalItems; x++) {
                JSONObject itemObj = resultArray.getJSONObject(x);
                int id = itemObj.getInt("id");
                String name = itemObj.getString("name");
                itemList.add(new Item(id, name));

                // 计算解析进度(占总进度的50%)
                int parseProgress = (int) (((x + 1) * 100) / totalItems);
                int totalProgress = 50 + (parseProgress / 2);
                publishProgress(totalProgress);
            }

            return itemList;
        } catch (IOException | JSONException e) {
            e.printStackTrace();
            return null;
        }
    }

    // 主线程更新进度:更新进度条和文本
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        int progress = values[0];
        mProgressBar.setProgress(progress);
        mProgressText.setText(progress + "%");
    }

    // 任务完成后:通知主线程处理结果
    @Override
    protected void onPostExecute(List<Item> items) {
        super.onPostExecute(items);
        if (items != null) {
            mListener.onLoadComplete(items);
            // 加载完成后隐藏进度控件
            mProgressBar.setVisibility(View.GONE);
            mProgressText.setVisibility(View.GONE);
        } else {
            mListener.onLoadFailed(new Exception("加载或解析JSON失败"));
        }
    }
}

第四步:在Activity中使用AsyncTask

在你的Activity里启动这个任务,并处理加载完成后的结果:

public class MainActivity extends AppCompatActivity implements LoadJsonTask.OnLoadCompleteListener {
    private ProgressBar mProgressBar;
    private TextView mProgressText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 绑定UI控件
        mProgressBar = findViewById(R.id.progressBar);
        mProgressText = findViewById(R.id.progressText);

        // 启动后台加载任务
        new LoadJsonTask(this, mProgressBar, mProgressText, this).execute();
    }

    // 加载完成后的回调:处理解析好的数据
    @Override
    public void onLoadComplete(List<Item> items) {
        Toast.makeText(this, "加载完成!共" + items.size() + "条数据", Toast.LENGTH_SHORT).show();
        // 这里可以把数据显示到RecyclerView或其他控件里,比如:
        // yourRecyclerView.setAdapter(new YourAdapter(items));
    }

    // 加载失败的回调:提示用户
    @Override
    public void onLoadFailed(Exception e) {
        Toast.makeText(this, "加载失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }
}

关键说明

  • doInBackground:所有耗时操作(读取文件、解析JSON)都在这里执行,完全不影响主线程,所以应用不会冻结。
  • publishProgress:后台线程中调用,用来把进度数据传递到主线程,触发onProgressUpdate更新UI。
  • 进度拆分:把加载过程分成读取文件(50%)和解析数据(50%),用户能看到完整的进度变化,体验更好。
  • 回调接口:解耦AsyncTask和Activity,避免直接持有Activity引用导致内存泄漏。

内容的提问来源于stack exchange,提问作者Taha Sami

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:07:38