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

如何在Android应用运行期间仅解析一次JSON数据?

实现Android应用JSON仅解析一次的解决方案

问题核心

当前应用在横竖屏切换、页面刷新、从子页面返回重建时,会重复执行JSON解析与网络请求,导致加载缓慢,多次切换甚至崩溃。现有代码尝试用AsyncTaskRunner加run标记控制,但未彻底解决问题,还存在数据库重复插入、主线程处理解析等冗余操作。


1. 优先读取本地数据库,避免重复网络请求

在发起网络请求前,先检查数据库是否已有数据。有数据直接读取展示,无数据再发起请求解析:

// Activity初始化时调用此方法替代直接调用parseApiData
private void loadData() {
    // 从本地数据库读取已有数据
    List<Books> savedBooks = dbHandler.readCourses();
    if (savedBooks != null && !savedBooks.isEmpty()) {
        books.clear();
        books.addAll(savedBooks);
        progressBar.setVisibility(View.GONE);
        recyclerView.setAdapter(new BookAdapter(MainActivity.this, books));
        return;
    }
    // 数据库无数据时,才发起网络请求
    parseApiData();
}

2. 修复JSON解析与数据库操作的冗余问题

现有代码存在重复插入数据库的错误(循环内插入一次,又开线程再插入一次),同时要把数据库操作放到后台线程,避免阻塞主线程:

// 修改parseApiData中的onResponse方法
@Override
public void onResponse(JSONArray response) {
    if (response != null && response.length() > 0) {
        books.clear();
        // 清空旧数据
        dbHandler.removeAll();

        for (int i = 0; i < response.length(); i++) {
            try {
                JSONObject obj = response.getJSONObject(i);
                int bookId = obj.getInt("id");
                String bookName = obj.getString("title");
                String bookDescription = obj.getString("description");
                int bookPage = obj.getInt("pageCount");
                String bookExcerpt = obj.getString("excerpt");
                String bookPublishDate = obj.getString("publishDate");
                
                Books book = new Books(bookId, bookName, bookDescription, bookPage, bookExcerpt, bookPublishDate);
                books.add(book);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        // 后台线程执行数据库插入,完成后主线程更新UI
        new Thread(() -> {
            for (Books book : books) {
                dbHandler.addNewCourse(book.getmBookId(), book.getmBookName(), book.getmBookDescription(), book.getmBookPage(), book.getmBookExcerpt(), book.getmBookPublishDate());
            }
            runOnUiThread(() -> {
                progressBar.setVisibility(View.GONE);
                recyclerView.setAdapter(new BookAdapter(MainActivity.this, books));
            });
        }).start();

    } else {
        runOnUiThread(() -> {
            progressBar.setVisibility(View.GONE);
            Toast.makeText(MainActivity.this, "数据为空", Toast.LENGTH_SHORT).show();
        });
    }
}

3. 避免Activity重建时重复请求

横竖屏切换会触发Activity重建,可通过两种方式解决:

方式一:配置Manifest禁用重建

在AndroidManifest.xml的对应Activity标签中添加:

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|screenLayout">
    <!-- 其他原有配置 -->
</activity>

这样横竖屏切换时Activity不会重建,仅调用onConfigurationChanged方法,无需重新初始化数据。

方式二:用ViewModel持久化数据

如果需要保留Activity重建逻辑,使用ViewModel保存数据,重建后直接复用:

// 自定义ViewModel类
public class BookViewModel extends ViewModel {
    private MutableLiveData<List<Books>> booksLiveData;
    private YourDbHandler dbHandler; // 替换为你的数据库操作类

    public LiveData<List<Books>> getBooks(Context context) {
        if (booksLiveData == null) {
            booksLiveData = new MutableLiveData<>();
            loadBooks(context);
        }
        return booksLiveData;
    }

    private void loadBooks(Context context) {
        dbHandler = new YourDbHandler(context);
        // 后台线程读取数据库
        Executors.newSingleThreadExecutor().execute(() -> {
            List<Books> savedBooks = dbHandler.readCourses();
            if (savedBooks != null && !savedBooks.isEmpty()) {
                booksLiveData.postValue(savedBooks);
                return;
            }
            // 数据库无数据,发起网络请求
            RequestQueue queue = Volley.newRequestQueue(context);
            JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, url, null,
                    response -> {
                        List<Books> newBooks = new ArrayList<>();
                        for (int i = 0; i < response.length(); i++) {
                            try {
                                JSONObject obj = response.getJSONObject(i);
                                Books book = new Books(
                                        obj.getInt("id"),
                                        obj.getString("title"),
                                        obj.getString("description"),
                                        obj.getInt("pageCount"),
                                        obj.getString("excerpt"),
                                        obj.getString("publishDate")
                                );
                                newBooks.add(book);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                        // 插入数据库后更新LiveData
                        Executors.newSingleThreadExecutor().execute(() -> {
                            dbHandler.removeAll();
                            for (Books book : newBooks) {
                                dbHandler.addNewCourse(book.getmBookId(), book.getmBookName(), book.getmBookDescription(), book.getmBookPage(), book.getmBookExcerpt(), book.getmBookPublishDate());
                            }
                            booksLiveData.postValue(newBooks);
                        });
                    },
                    error -> Toast.makeText(context, "网络请求失败", Toast.LENGTH_SHORT).show());
            queue.add(request);
        });
    }
}

在Activity中使用ViewModel:

public class MainActivity extends AppCompatActivity {
    private BookViewModel viewModel;

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

        viewModel = new ViewModelProvider(this).get(BookViewModel.class);
        viewModel.getBooks(this).observe(this, books -> {
            if (books != null) {
                progressBar.setVisibility(View.GONE);
                recyclerView.setAdapter(new BookAdapter(this, books));
            }
        });
    }
}

4. 移除无效的AsyncTask逻辑

现有AsyncTaskRunner中的run标记是Activity成员变量,重建后会重置为默认值false,无法有效控制重复请求,建议直接删除该AsyncTask,改用上述方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 07:15:32