J'ai réduit mon problème à un problème avec le FragmentManager conservant des instances d'anciens fragments et mon viewpager n'étant pas synchronisé avec mon FragmentManager. Voir ce problème : http://code.google.com/p/Android/issues/detail?id=19211#makechanges . Je n'ai toujours aucune idée de la façon de résoudre ce problème. Avez-vous des suggestions ?
J'ai essayé de déboguer ce problème depuis longtemps et toute aide serait grandement appréciée. J'utilise un FragmentPagerAdapter qui accepte une liste de fragments comme suit :
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName()));
...
new PagerAdapter(getSupportFragmentManager(), fragments);
L'implémentation est standard. J'utilise ActionBarSherlock et la bibliothèque de calculabilité v4 pour Fragments.
Mon problème est qu'après avoir quitté l'application, ouvert plusieurs autres applications et être revenu, les fragments perdent leur référence à l'activité FragmentActivity (c'est-à-dire qu'ils ne peuvent plus être utilisés comme référence à l'activité Fragment). getActivity() == null
). Je n'arrive pas à comprendre pourquoi cela se produit. J'ai essayé de définir manuellement setRetainInstance(true);
mais cela n'aide pas. Je me suis dit que cela se produisait lorsque mon FragmentActivity était détruit, mais cela se produit toujours si j'ouvre l'application avant d'obtenir le message du journal. Avez-vous une idée ?
@Override
protected void onDestroy(){
Log.w(TAG, "DESTROYDESTROYDESTROYDESTROYDESTROYDESTROYDESTROY");
super.onDestroy();
}
L'adaptateur :
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
@Override
public int getCount() {
return this.fragments.size();
}
}
Un de mes fragments a été supprimé mais j'ai commenté tout ce qui a été supprimé et ça ne fonctionne toujours pas.
public class MyFragment extends Fragment implements MyFragmentInterface, OnScrollListener {
...
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
handler = new Handler();
setHasOptionsMenu(true);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.w(TAG,"ATTACHATTACHATTACHATTACHATTACH");
context = activity;
if(context== null){
Log.e("IS NULL", "NULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULL");
}else{
Log.d("IS NOT NULL", "NOTNOTNOTNOTNOTNOTNOTNOT");
}
}
@Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.my_fragment,container, false);
return v;
}
@Override
public void onResume(){
super.onResume();
}
private void callService(){
// do not call another service is already running
if(startLoad || !canSet) return;
// set flag
startLoad = true;
canSet = false;
// show the bottom spinner
addFooter();
Intent intent = new Intent(context, MyService.class);
intent.putExtra(MyService.STATUS_RECEIVER, resultReceiver);
context.startService(intent);
}
private ResultReceiver resultReceiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, final Bundle resultData) {
boolean isSet = false;
if(resultData!=null)
if(resultData.containsKey(MyService.STATUS_FINISHED_GET)){
if(resultData.getBoolean(MyService.STATUS_FINISHED_GET)){
removeFooter();
startLoad = false;
isSet = true;
}
}
switch(resultCode){
case MyService.STATUS_FINISHED:
stopSpinning();
break;
case SyncService.STATUS_RUNNING:
break;
case SyncService.STATUS_ERROR:
break;
}
}
};
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.activity, menu);
}
@Override
public void onPause(){
super.onPause();
}
public void onScroll(AbsListView arg0, int firstVisible, int visibleCount, int totalCount) {
boolean loadMore = /* maybe add a padding */
firstVisible + visibleCount >= totalCount;
boolean away = firstVisible+ visibleCount <= totalCount - visibleCount;
if(away){
// startLoad can now be set again
canSet = true;
}
if(loadMore)
}
public void onScrollStateChanged(AbsListView arg0, int state) {
switch(state){
case OnScrollListener.SCROLL_STATE_FLING:
adapter.setLoad(false);
lastState = OnScrollListener.SCROLL_STATE_FLING;
break;
case OnScrollListener.SCROLL_STATE_IDLE:
adapter.setLoad(true);
if(lastState == SCROLL_STATE_FLING){
// load the images on screen
}
lastState = OnScrollListener.SCROLL_STATE_IDLE;
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
adapter.setLoad(true);
if(lastState == SCROLL_STATE_FLING){
// load the images on screen
}
lastState = OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
break;
}
}
@Override
public void onDetach(){
super.onDetach();
if(this.adapter!=null)
this.adapter.clearContext();
Log.w(TAG, "DETACHEDDETACHEDDETACHEDDETACHEDDETACHEDDETACHED");
}
public void update(final int id, String name) {
if(name!=null){
getActivity().getSupportActionBar().setTitle(name);
}
}
}
La méthode de mise à jour est appelée lorsqu'un utilisateur interagit avec un autre fragment et que la méthode getActivity renvoie null. Voici la méthode que l'autre fragment appelle :
((MyFragment) pagerAdapter.getItem(1)).update(id, name);
Je crois que lorsque l'application est détruite puis recréée, au lieu de démarrer l'application sur le fragment par défaut, l'application démarre et le viewpager navigue sur la dernière page connue. Cela semble étrange, l'application ne devrait-elle pas simplement se charger sur le fragment par défaut ?
28 votes
Le Fragment d'Android est nul !
13 votes
Mon Dieu, j'adore vos messages de journal :D