如何在Activity的onOptionsItemSelected中刷新ViewPager内的Fragment?
Hey there! Let's figure out why your app is crashing when you tap the refresh icon and fix it step by step.
What's Causing the Crash?
Your code has two critical issues that lead to the crash:
Null Fragments from Wrong Tag Lookup
You're trying to find Fragments using tags like"fragmentSentMsg", but that's the tag you set on the Fragment's root View (Page2_sent_msg.setTag("sentMsg");), not the tag the FragmentManager uses to track the Fragment itself. ViewPager generates its own system tags for Fragments, sofindFragmentByTag()returns null here — leading to aNullPointerExceptionwhen you try todetach()these null references.Reusing the Same FragmentTransaction Multiple Times
You create oneFragmentTransaction, add multiple detach/attach operations, then callcommit()three times. A single transaction can only be committed once, so this will throw an exception.
Solution 1: Add a Refresh Method to Each Fragment (Recommended)
This is a cleaner, more flexible approach than detaching/attaching, as you have direct control over what gets refreshed.
Step 1: Update Fragments with a Refresh Method
Modify your Page2_sent_msg Fragment (and the other two) to move data loading into a reusable method:
public class Page2_sent_msg extends Fragment { private ListView sentMsgListView; private ArrayAdapter<String> sentMsgAdapter; private ArrayList<String> sentMsgArrayList; // Default constructor public Page2_sent_msg(){} @SuppressLint("ResourceType") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ final View rootView = inflater.inflate(R.layout.page2_sent_msg, container, false); sentMsgListView = rootView.findViewById(R.id.sentMsgListview); sentMsgArrayList = new ArrayList<>(); sentMsgAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, sentMsgArrayList); sentMsgListView.setAdapter(sentMsgAdapter); // Keep your existing item click logic sentMsgListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // Your existing click handler } }); // Load initial data loadSentMessages(); return rootView; } // Public method to trigger refresh public void refresh() { loadSentMessages(); } private void loadSentMessages() { sentMsgArrayList.clear(); // Clear old data first SQLite_database_helper_class myDb = new SQLite_database_helper_class(getContext()); Cursor result = myDb.getting_sms_from_db(); if (result.moveToFirst()) { do { if (!result.getString(3).equals("Sent message")) { continue; } sentMsgArrayList.add( "SMS No : "+result.getString(0)+"\n" + "Address : "+result.getString(1)+"\n" + "Date : "+result.getString(2)+"\n" + "Type : "+result.getString(3)+"\n" + "Content : " +"\n________\n\n"+result.getString(4)+"\n" ); } while (result.moveToNext()); } sentMsgAdapter.notifyDataSetChanged(); // Tell adapter data has updated result.close(); // Avoid cursor leaks! } }
Repeat this pattern for your receivedMsg and allMsg Fragments, adding their own refresh() and data loading methods.
Step 2: Call Refresh from the Activity
In your Activity's onOptionsItemSelected, get the Fragments from the ViewPager's adapter and call their refresh methods:
@Override public boolean onOptionsItemSelected(MenuItem item){ switch (item.getItemId()){ case R.id.refresher_id: // Get your ViewPager instance (replace with your ViewPager's ID) ViewPager viewPager = findViewById(R.id.your_viewpager_id); FragmentPagerAdapter adapter = (FragmentPagerAdapter) viewPager.getAdapter(); // Get Fragments by position (adjust positions to match your ViewPager order) Page2_sent_msg sentMsgFragment = (Page2_sent_msg) adapter.getItem(0); PageReceivedMsg receivedMsgFragment = (PageReceivedMsg) adapter.getItem(1); PageAllMsg allMsgFragment = (PageAllMsg) adapter.getItem(2); sentMsgFragment.refresh(); receivedMsgFragment.refresh(); allMsgFragment.refresh(); break; } return super.onOptionsItemSelected(item); }
Solution 2: Fix the Detach/Attach Approach
If you prefer to use detach/attach to refresh, fix the Fragment lookup and transaction handling:
@Override public boolean onOptionsItemSelected(MenuItem item){ switch (item.getItemId()){ case R.id.refresher_id: FragmentManager fm = getSupportFragmentManager(); // ViewPager's system tag format: "android:switcher:" + viewPagerId + ":" + position int viewPagerId = R.id.your_viewpager_id; // Replace with your ViewPager's ID Fragment sentMsg = fm.findFragmentByTag("android:switcher:" + viewPagerId + ":0"); Fragment receivedMsg = fm.findFragmentByTag("android:switcher:" + viewPagerId + ":1"); Fragment allMsg = fm.findFragmentByTag("android:switcher:" + viewPagerId + ":2"); // Use separate transactions for each Fragment (or add all ops to one transaction) if (sentMsg != null) { fm.beginTransaction().detach(sentMsg).attach(sentMsg).commit(); } if (receivedMsg != null) { fm.beginTransaction().detach(receivedMsg).attach(receivedMsg).commit(); } if (allMsg != null) { fm.beginTransaction().detach(allMsg).attach(allMsg).commit(); } break; } return super.onOptionsItemSelected(item); }
Note: This will re-run the Fragment's onCreateView method, so ensure your data loading logic clears old data before adding new items.
Extra Tips
- Always check if Fragments are not null before performing operations to avoid
NullPointerException. - Close database cursors after use to prevent memory leaks.
- If using
FragmentStatePagerAdapter,getItem()may create new Fragment instances — use the tag-based lookup from Solution 2 to get existing Fragments.
内容的提问来源于stack exchange,提问作者Mugirase Emmanuel

