I am writing an application that uses fragments on the main screen. The general idea is this: there are 4 tables on the server, data from each table comes from the server and is displayed on one of the fragments. I cite the code for 1 taba, the other 3 are written as well. To initialize the fragments I use the heir of the FragmentPagerAdapter class, the data is received in the form of an ArrayList.

public class TabsFragmentAdapter extends FragmentPagerAdapter { private Map<Integer, AbstractTabFragment> tabs; private Context context; private List<TournamentsDTO> data_tour; private List<TeamsDTO> data_team; private List<PlayersDTO> data_play; private List<CommentatorsDTO> data_comm; private TournamentsFragment tournamentsFragment; private TeamsFragment teamsFragment; private PlayersFragment playersFragment; private CommentatorsFragment commentatorsFragment; public TabsFragmentAdapter(Context context, FragmentManager fm) { super(fm); this.context = context; this.data_tour = new ArrayList<>(); this.data_team = new ArrayList<>(); this.data_play = new ArrayList<>(); this.data_comm = new ArrayList<>(); initTabs(context); } @Override public CharSequence getPageTitle(int position) { return tabs.get(position).getTitle(); } @Override public Fragment getItem(int position) { return tabs.get(position); } @Override public int getCount() { return tabs.size(); } private void initTabs(Context context) { tabs = new HashMap<>(); tournamentsFragment = TournamentsFragment.getInstance(context, data_tour); teamsFragment = TeamsFragment.getInstance(context, data_team); playersFragment = PlayersFragment.getInstance(context, data_play); commentatorsFragment = CommentatorsFragment.getInstance(context, data_comm); tabs.put(0, tournamentsFragment); tabs.put(1, teamsFragment); tabs.put(2, playersFragment); tabs.put(3, commentatorsFragment); } public void setData_tour(List<TournamentsDTO> data_tour) { this.data_tour = data_tour; tournamentsFragment.refreshData(data_tour); } public void setData_team(List<TeamsDTO> data_team) { this.data_team = data_team; teamsFragment.refreshData(data_team); } public void setData_play(List<PlayersDTO> data_play) { this.data_play = data_play; playersFragment.refreshData(data_play); } public void setData_comm(List<CommentatorsDTO> data_comm) { this.data_comm = data_comm; commentatorsFragment.refreshData(data_comm); } 

Here is the initialization of each fragment.

 public class TournamentsFragment extends AbstractTabFragment { private static final int LAYOUT = R.layout.fragment_tournaments; private List<TournamentsDTO> data_tour; private TournamentsListAdapter tournamentsListAdapter; public static TournamentsFragment getInstance(Context context, List<TournamentsDTO> data_tour) { Bundle args = new Bundle(); TournamentsFragment tournamentsFragment = new TournamentsFragment(); tournamentsFragment.setArguments(args); tournamentsFragment.setContext(context); tournamentsFragment.setData_tour(data_tour); tournamentsFragment.setTitle(context.getString(R.string.fab_item_tournaments)); return tournamentsFragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { view = inflater.inflate(LAYOUT, container, false); RecyclerView rv = (RecyclerView) view.findViewById(R.id.recyclerViewTour); rv.setLayoutManager(new LinearLayoutManager(context)); tournamentsListAdapter = new TournamentsListAdapter(data_tour); rv.setAdapter(tournamentsListAdapter); return view; } private void setContext(Context context) { this.context = context; } private void setData_tour(List<TournamentsDTO> data_tour) { this.data_tour = data_tour; } public void refreshData(List<TournamentsDTO> list){ tournamentsListAdapter.setData_tour(list); tournamentsListAdapter.notifyDataSetChanged(); } 

And this is how they are filled in MainActivity. Here I present global variables, a method that initializes tabs and a method that loads data from a server. The data comes in the form of an array, so I translate them into a list.

 public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private TabsFragmentAdapter adapter1, adapter2, adapter3, adapter4; private void initTabs() { viewPager = (ViewPager) findViewById(R.id.viewPager); adapter1 = new TabsFragmentAdapter(this, getSupportFragmentManager()); viewPager.setAdapter(adapter1); new TournamentTask().execute(); TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout); tabLayout.setupWithViewPager(viewPager); } private class TournamentTask extends AsyncTask<Void, Void, TournamentsDTO[]>{ @Override protected TournamentsDTO[] doInBackground(Void... params) { RestTemplate template1 = new RestTemplate(); template1.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); return template1.getForObject(Constants.URL.GET_ALL_TOURNAMENTS_ITEM, TournamentsDTO[].class); } @Override protected void onPostExecute(TournamentsDTO[] tournamentsDTOs) { List<TournamentsDTO> listTour = new ArrayList<>(); int count = 0; while (count < tournamentsDTOs.length){ listTour.add(tournamentsDTOs[count]); count++; } adapter1.setData_tour(listTour); } } 

Here are the errors that appear

 Process: illidan.com.statisticsd2, PID: 5888 java.lang.NullPointerException at illidan.com.statisticsd2.fragments.TournamentsFragment.refreshData(TournamentsFragment.java:68) at illidan.com.statisticsd2.adapter.TabsFragmentAdapter.setData_tour(TabsFragmentAdapter.java:79) at illidan.com.statisticsd2.MainActivity$TournamentTask.onPostExecute(MainActivity.java:169) at illidan.com.statisticsd2.MainActivity$TournamentTask.onPostExecute(MainActivity.java:151) at android.os.AsyncTask.finish(AsyncTask.java:632) at android.os.AsyncTask.access$600(AsyncTask.java:177) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5001) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) 

Thanks for any help!

  • And it’s also funny that while the code works only for one tab there are no errors, but when I try to run 2 and more, the problems start. - Illidan Stormrage 7:49 pm
  • If you are given an exhaustive answer, mark it as correct (a daw opposite the selected answer). - Nicolas Chabanovsky

1 answer 1

You have created fragments in the adapter (TabsFragmentAdapter), but the life cycle for them has not yet begun, i.e. onCreateView is not called, it is called only for the currently displayed fragment. As a result, your tournamentsListAdapter is not initialized, and you are trying to update the data to it.

As an option:

 public void refreshData(List<TournamentsDTO> list){ if(tournamentsListAdapter==null){ data_tour = list; } else { tournamentsListAdapter.setData_tour(list); tournamentsListAdapter.notifyDataSetChanged(); } } 

In addition, you incorrectly initialize the fragment, the factory method getInstance should only fill in the arguments, the remaining fields will be cleared when the fragment is recreated (when rotated). These lines are incorrect:

 tournamentsFragment.setContext(context); tournamentsFragment.setData_tour(data_tour); tournamentsFragment.setTitle(context.getString(R.string.fab_item_tournaments)); 

Further, it is not necessary to transfer the context to the fragment, the fragment has a getContext () method. The rest of the data can either be serialized (for example, you can safely write the title to the arguments) to the arguments, or call the appropriate methods from the activation (that is, from the outside), considering (see the first snippet) that the fragment is not necessarily displayed.

UPD

getInstance might look like this:

 public static TournamentsFragment getInstance(String title) { Bundle args = new Bundle(); TournamentsFragment tournamentsFragment = new TournamentsFragment(); args.putString("title", title); tournamentsFragment.setArguments(args); return tournamentsFragment; } 

Use this:

 tournamentsFragment = TournamentsFragment.getInstance( context.getString(R.string.fab_item_tournaments)); 

As for the data, they are not needed in getInstance, you still create fragments with empty lists and wait for them in AsyncTask ... You need to look at the list adapter, or rather the setData_tour method. Well, in general, without seeing your full code, you can assume a lot ... Use the debugger, see which methods for which fragment are called in what order, whether the list is filled, whether the adapter is updated, etc.

Threat Analyze whether you need a variable list for the data in the TabsFragmentAdapter, if you still translate them into the corresponding fragment, and from there to the adapter.

  • With the first part of the answer, everything is clear, but I cannot figure out how to get rid of these three wrong lines. In addition, I changed the refreshData () according to your advice and now the data is displayed only on one of the fragments, regardless of which of the fragments is now shown (well, at least there is no NPE now). Could you explain in more detail the second part of the advice, please. - Illidan Stormrage
  • @IllidanStormrage updated the answer. - Yura Ivanov
  • Infinitely grateful to you, the problem was solved. When I thought with my head, even the first part of the answer was enough (checking for null). But here's another odd thing: when I switch from the first tab to the second, and then back to the first, the data on the first one is saved. When I switch from the first to the second, and then to the third, then the data on the second tab still remains, but on the first tab it is deleted. - Illidan Stormrage
  • I suspect that the matter is in the implementation of the adapter, i. Fragments should be created as needed by the viewPager. You have fragments created in advance, the viewpager removes unnecessary fragments. Try adding viewPager.setOffscreenPageLimit(3); then your fragments should not be deleted and the data will remain. - Yura Ivanov