android - ¿Cómo mantener las instancias de vista creadas en onCreateView de Fragment en ViewPager cuando se reanuda el fragmento?
android-fragments android-asynctask (2)
Finalmente obtuve la solución. Es muy sencillo.
- Eliminé la implementación de la interfaz FragmentLifecycle.
Se agregó el siguiente método a cada fragmento.
@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if(isVisibleToUser && !isDataLoaded){ getVocalistList(Gender.All); isDataLoaded = true; } }
Funciona como magia. No necesito preocuparme por perder la instancia de RecyclerView
ya que no era nula cuando se setUserVisibleHint
método setUserVisibleHint
.
La historia es que hay cinco fragmentos en ViewPager y cada fragmento tiene que ejecutar una AsyncTask cuando aparece en ViewPager. Estoy intentando exactamente lo mismo que la respuesta correcta aquí . Puse mi AsyncTask
onResumeFragment
y funciona bien. Pero el problema comienza cuando actualizo la vista después de que AsyncTask
ejecute correctamente. Porque la vista (RecyclerView) que creé en onCreateView está siendo nula cuando actualizo el conjunto de datos. También probé setRetainInstance(true)
dentro onActivityCreated
. No funcionó.
Aquí está mi código,
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Tab & Pager
viewPager = (ViewPager) findViewById(R.id.main_tab_content);
adapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
addPagerListener();
}
private void addPagerListener(){
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int newPosition) {
FragmentLifecycle fragmentToShow = (FragmentLifecycle)adapter.getItem(newPosition);
fragmentToShow.onResumeFragment();
FragmentLifecycle fragmentToHide = (FragmentLifecycle)adapter.getItem(currentPosition);
fragmentToHide.onPauseFragment();
currentPosition = newPosition;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
switch (position){
case 0: return new HomeFragment();
case 1: return new ArtistFragment();
case 2: return new AlbumsFragment();
case 3: return new CollectionsFragment();
case 4: return new SavedFragments();
default: return null;
}
}
@Override
public int getCount() {
return 5;
}
}
Aquí está mi código del 2 ° Fragmento, los fragmentos restantes están en blanco hasta el momento.
public class ArtistFragment extends Fragment implements FragmentLifecycle{
@BindView(R.id.recyclerview_frag_artist)
RecyclerView mRecyclerView;
RecyclerView.Adapter mAdapter;
RecyclerView.LayoutManager mLayoutManager;
@BindView(R.id.radioBtnAll_frag_artist)
RadioButton radioAll;
@BindView(R.id.radioBtnMale_frag_artist)
RadioButton radioMale;
@BindView(R.id.radioBtnFemale_frag_artist)
RadioButton radioFemale;
ArrayList<String> vocalistNameList;
Context context;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_artists, container, false);
ButterKnife.bind(this, rootView);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(rootView.getContext());
mRecyclerView.setLayoutManager(mLayoutManager);
vocalistNameList = getDummyDS();
mAdapter = new MyListAdapter(vocalistNameList);
mRecyclerView.setAdapter(mAdapter);
radioAll.setChecked(true);
return rootView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
}
private ArrayList<String> getDummyDS(){
ArrayList<String> dataset = new ArrayList<>();
dataset.add("test");
dataset.add("test");
dataset.add("test");
dataset.add("test");
dataset.add("test");
dataset.add("test");
dataset.add("test");
return dataset;
}
private void getVocalistList(Gender gender){
RequestParams params = new RequestParams();
params.put("action","query");
params.put("list","allcategories");
params.put("acprefix","Vocalist-");
params.put("format","json");
params.put("aclimit","5000");
MyRestClient.get("", params, new JsonHttpResponseHandler(){
ProgressDialog progress;
@Override
public void onStart() {
progress = ProgressDialog.show(AppConstants.activity, "Please wait",
"Loading data..", true);
progress.setCancelable(true);
}
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
progress.dismiss();
vocalistNameList = new ArrayList<String>();
try {
JSONArray vocalListJsonArray = response.getJSONObject("query").getJSONArray("allcategories");
for(int i=0; i<vocalListJsonArray.length(); i++){
String vocalListName = vocalListJsonArray.getJSONObject(i).getString("*").replace("Vocalist-","");
vocalistNameList.add(vocalListName);
}
mAdapter = new MyListAdapter(vocalistNameList);
mRecyclerView.setAdapter(mAdapter); // <= RecyclerView is null and app is crashing
mAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
progress.dismiss();
Log.i("failure", "failed "+statusCode);
}
});
}
@Override
public void onPauseFragment() {
Toast.makeText(AppConstants.applicationContext, "onPauseFragment():", Toast.LENGTH_SHORT).show();
}
@Override
public void onResumeFragment() {
getVocalistList(Gender.All);
Toast.makeText(AppConstants.applicationContext, "onResumeFragment(): Artist", Toast.LENGTH_SHORT).show();
}
He estado tratando de resolver ese problema desde hace una semana. ¿Alguna idea? (PD estoy usando Android Asynchronous Http Client en lugar de AsyncTask
)
Tienes que hacer algo como esto:
pager.setOffscreenPageLimit([quantity of tabs that you would like to keep in memory]);
Eche un vistazo a esta respuesta. ViewPager dentro de Fragment pierde contenido al volver a él