实现 Fragment 实例化会产生相反的效果
Implementing Fragment instantiation causes opposite effect
I have implemented my fragment to the Android's best practice of using newInstance
with parameters. 可以,但有一个舱口。
带参数的 newInstance
修复的问题是 Android 将在屏幕旋转时调用默认的无参数构造函数。这意味着您将丢失轮换数据。 newInstance
将允许您 setArguments
将保留轮换。
使用 overloaded constructor
意味着您的数据将在第一次正确显示,直到您旋转设备。 newInstance
将使您的片段在第一次和轮换时都能正常工作。
问题
然而,我好像适得其反。我的代码在旋转时工作正常,但在第一次尝试时工作不正常。如果我使用带参数的构造函数,也会出现同样的效果。
应用程序加载时,它会在 Tablayout
中显示我的选项卡 (3),但我的 RecyclerView
中的 none 将包含项目。
以下是我如何以最快的速度将数据加载到 RecyclerView
中。全部在应用程序加载中,并且全部从新开始:
- 旋转设备。所有 3 个选项卡都将加载它们的数据。现在是当前选项卡,选择其他选项卡(滑动到它们)。
- 从第一个选项卡,单击选项卡 3,然后返回选项卡 1。将加载选项卡 1 的数据。标签 2 不会加载。选项卡 3 将在选择时加载。要加载 Tab 2 数据,我需要旋转设备
代码
片段
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;
}
}
}
基础活动
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);
}
}
只要异步任务完成它的工作,您就需要更新适配器并通知它的项目有变化。
更新适配器视图需要在主线程中,所以请在您的任务中添加以下方法:
@Override
protected void onPostExecute(Void nothing) {
adapter.notifyDataSetChanged();
}
I have implemented my fragment to the Android's best practice of using newInstance
with parameters. 可以,但有一个舱口。
带参数的 newInstance
修复的问题是 Android 将在屏幕旋转时调用默认的无参数构造函数。这意味着您将丢失轮换数据。 newInstance
将允许您 setArguments
将保留轮换。
使用 overloaded constructor
意味着您的数据将在第一次正确显示,直到您旋转设备。 newInstance
将使您的片段在第一次和轮换时都能正常工作。
问题
然而,我好像适得其反。我的代码在旋转时工作正常,但在第一次尝试时工作不正常。如果我使用带参数的构造函数,也会出现同样的效果。
应用程序加载时,它会在 Tablayout
中显示我的选项卡 (3),但我的 RecyclerView
中的 none 将包含项目。
以下是我如何以最快的速度将数据加载到 RecyclerView
中。全部在应用程序加载中,并且全部从新开始:
- 旋转设备。所有 3 个选项卡都将加载它们的数据。现在是当前选项卡,选择其他选项卡(滑动到它们)。
- 从第一个选项卡,单击选项卡 3,然后返回选项卡 1。将加载选项卡 1 的数据。标签 2 不会加载。选项卡 3 将在选择时加载。要加载 Tab 2 数据,我需要旋转设备
代码
片段
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;
}
}
}
基础活动
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);
}
}
只要异步任务完成它的工作,您就需要更新适配器并通知它的项目有变化。
更新适配器视图需要在主线程中,所以请在您的任务中添加以下方法:
@Override
protected void onPostExecute(Void nothing) {
adapter.notifyDataSetChanged();
}