I have implemented my fragment to the Android's best practice of using newInstance
with parameters. It works, but with a hatch.
The issue the newInstance
with parameters fixes is that Android will call the default no-args constructor on screen rotation. That means you will lose data on rotation. The newInstance
will allow you to setArguments
that will be retained on rotation.
Using the overloaded constructor
will mean your data will show correctly the first time until you rotate your device. The newInstance
will allow your fragment to work correctly the first time and on rotations.
Issues
However, it seems like I am having the opposite effect. My code works correctly on rotations, but does not work correctly on the first try. The same effect occurs if I use the constructor with arguments.
On app load, it will display my tabs (3) in a Tablayout
but none of my RecyclerView
s will have items in them.
Here is how I can load data into the RecyclerView
s the fastest. All on app load, and all are from fresh starts:
- Rotate the device. All 3 tabs will load their data. Current tab right now, and other tabs on selection (sliding to them).
- From 1st Tab, click on Tab 3, then go back to Tab 1. Tab 1 data will load. Tab 2 won't load. Tab 3 will load on selection. To get Tab 2 data to load, I need to rotate the device
Code
Fragment
public class MovieListFragment extends Fragment implements OnItemClickListener {
MovieListAdapter adapter;
WebAPI webAPI; // Advanced Enum
private static final String API_STRING = "api";
public MovieListFragment() {}
public static MovieListFragment newInstance(WebAPI API) {
MovieListFragment fragment = new MovieListFragment();
Bundle args = new Bundle();
args.putSerializable(API_STRING, API);
fragment.setArguments(args);
// if (API != null) fragment.webAPI = API;
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_movies_list, container, false);
webAPI = (WebAPI) getArguments().getSerializable(API_STRING);
GetMoviesAsync getMovies = new GetMoviesAsync();
getMovies.execute();
adapter = new MovieListAdapter(getActivity(), webAPI, this);
RecyclerView movieListView;
movieListView = (RecyclerView) rootView.findViewById(R.id.movie_list);
movieListView.setAdapter(adapter);
movieListView.setLayoutManager(
new GridLayoutManager( // Changes number of columns based on form-factor and orientation
getActivity(),
getResources().getInteger(R.integer.columns)));
return rootView;
}
@Override
public void onClick(View v, int position) {
startActivity(new Intent(this.getActivity(), SecondaryActivity.class)); // TODO pass data to second activity
}
// ASYNC_TASK
public class GetMoviesAsync extends AsyncTask<Void, Void, Void> {
// CALLBACK
private final Handler.Callback getMoviesFromJSON = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// Take the JSON (msg) and convert it to a Java object (Movie)
Movie movie = new Movie(title, uri);
webAPI.addMovie(movie);
}
} catch (JSONException e) { return false; }
return true;
}
};
@Override
protected Void doInBackground(Void... params) {
try {
// This will get the JSON from the webservice, and will use the CallBack to assign the List of movies.
new WebService(webAPI.getUri()).acquireDataWithCallback(getMoviesFromJSON);
} catch (JSONException e) { e.printStackTrace(); }
return null;
}
}
}
BaseActivity
public abstract class BaseSearchTabbedActivity extends AppCompatActivity
implements SearchView.OnQueryTextListener {
EnumSet<WebAPI> tabs;
...
public void setTabs(EnumSet<WebAPI> tabs) { this.tabs = tabs; }
void initializeToolbar() { // Called in Activity's OnCreate
// Setup the toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Initialize all components. Tabs, Pager, and Adapter
tabLayout = (TabLayout) findViewById(R.id.tabs);
viewPager = (ViewPager) findViewById(R.id.pager);
adapter = new ViewPagerFragmentAdapter(getSupportFragmentManager());
// Add the tabs
collectTabValues(); // Set tabs from Activity
addFragments(tabs);
// Bind the adapter to the tabs
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
}
private void addFragments(EnumSet<WebAPI> tabs) {
for (WebAPI tab : tabs) {
adapter.addFragment(MovieListFragment.newInstance(tab), tab);
}
}