Android ViewPager+Fragment Volley空对象引用错误及优化方案咨询
Hey there, let's break down your problem step by step and figure out the best fixes!
1. Why the NullPointerException Occurs
The crash happens because when you switch ViewPager pages beyond the setOffscreenPageLimit value, the unused Fragments get detached from the Activity (their getActivity() returns null). If a Volley network request finishes after the Fragment is detached, calling getActivity().getApplicationContext() in the onResponse callback will throw a null pointer—since there's no longer an Activity attached to the Fragment.
2. Fix the NullPointerException
Here are two robust solutions to avoid this issue without forcing all Fragments to stay in memory:
Option 1: Check Fragment Attachment Before Using Context
Add a check to ensure the Fragment is still attached to an Activity before accessing any context-related methods in your Volley callbacks:
@Override public void onResponse(JSONObject response) { // Exit early if Fragment is no longer attached to Activity if (!isAdded()) { return; } LastWolrdNewsParser parser = new LastWolrdNewsParser(); ArrayList<LastWorldNews> news = parser.ParseJson(response); // Use getContext() instead of getActivity().getApplicationContext() for safer context access LastWorldNewsAdapter adapter = new LastWorldNewsAdapter(getContext(), R.layout.last_world_news_list_item, news); pb.setVisibility(View.GONE); if (mListView.getVisibility() == View.INVISIBLE || mListView.getVisibility() == View.GONE){ mListView.setVisibility(View.VISIBLE); } mListView.setAdapter(adapter); }
Do the same check in your error callback:
@Override public void onErrorResponse(VolleyError error) { if (!isAdded()) { return; } pb.setVisibility(View.GONE); }
getContext() is a better choice here than getActivity().getApplicationContext() because it's tied to the Fragment's lifecycle and won't cause issues if the Fragment is properly attached.
Option 2: Use ViewModel to Manage Data
For a more scalable fix, move your network request and data storage logic to a ViewModel. ViewModels survive Fragment lifecycle changes (like detaching/reattaching from the Activity), so even if the Fragment is destroyed, the request can complete and the data will be retained. When the Fragment is recreated, it can fetch the cached data from the ViewModel instead of making a new request.
3. About setOffscreenPageLimit
Setting setOffscreenPageLimit to 6 will keep all 7 Fragments in memory, which avoids the crash but is not ideal—it will significantly increase your app's memory usage, especially if each Fragment loads large list data. The solutions above are far better because they let the system manage memory efficiently while preventing the null pointer.
4. Is Canceling Volley Requests in onPause/onDestroy Standard?
Your approach is correct, but there's a small bug to fix first:
- Your
requestvariable is local to theprepareData()method, so it's not accessible inonPauseoronDestroy. You need to declare it as a member variable of the Fragment:
private JsonObjectRequest request; // Declare as Fragment member private void prepareData() { request = new JsonObjectRequest(Request.Method.GET, url, null, ...); RequestQueue quew = Volley.newRequestQueue(getContext()); quew.add(request); }
Canceling requests in onPause is smart because it stops unnecessary network activity when the Fragment is not visible. Double-checking in onDestroy adds an extra layer of protection against memory leaks, even though Volley's RequestQueue will automatically clean up requests when the Activity is destroyed.
内容的提问来源于stack exchange,提问作者Sadegh

