29

W aplikacji, którą opracowuję, używam ViewPagera z fragmentami i każdy fragment tworzy własne menu niezależnie od wszystkich innych fragmentów w ViewPager.Elementy akcji z początkowego fragmentu Viewpagera nie są wyświetlane

Problem polega na tym, że czasami fragmenty zainicjowane domyślnie przez ViewPager (tj. W stanie początkowym) nie mają odpowiednich elementów w menu elementów akcji. Co gorsza, problem ten pojawia się tylko sporadycznie. Jeśli przeskoczę przez ViewPager na tyle, że fragmenty są zmuszone do ponownego zainicjowania ich samych, po przesunięciu do tyłu menu zapełnia się prawidłowo.

kod aktywny:

package net.solarnz.apps.fragmentsample; 

import android.app.Activity; 
import android.app.Fragment; 
import android.app.FragmentManager; 
import android.os.Bundle; 
import android.support.v13.app.FragmentStatePagerAdapter; 
import android.support.v4.view.ViewPager; 

public class FragmentSampleActivity extends Activity { 
    private ViewPagerAdapter mViewPagerAdapter; 
    private ViewPager mViewPager; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     if (mViewPagerAdapter == null) { 
      mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager()); 
     } 

     mViewPager = (ViewPager) findViewById(R.id.log_pager); 
     mViewPager.setAdapter(mViewPagerAdapter); 
     mViewPager.setCurrentItem(0); 
    } 


    private class ViewPagerAdapter extends FragmentStatePagerAdapter { 
     public ViewPagerAdapter(FragmentManager fm) { 
      super(fm); 
     } 

     @Override 
     public int getCount() { 
      return 8; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      Fragment f = Fragment1.newInstance(position); 
      // f.setRetainInstance(true); 
      f.setHasOptionsMenu(true); 
      return f; 
     } 
    } 
} 

fragment kodu:

package net.solarnz.apps.fragmentsample; 

import android.app.Fragment; 
import android.os.Bundle; 
import android.view.Menu; 
import android.view.MenuInflater; 

public class Fragment1 extends Fragment { 
    int mNum; 

    static Fragment newInstance(int num) { 
     Fragment1 f = new Fragment1(); 

     // Supply num input as an argument. 
     Bundle args = new Bundle(); 
     args.putInt("num", num); 
     f.setArguments(args); 

     return f; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setHasOptionsMenu(true); 
     mNum = getArguments() != null ? getArguments().getInt("num") : 0; 
    } 

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     inflater.inflate(R.menu.menu_list, menu); 
    } 

} 

Układ:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" > 

      <android.support.v4.view.ViewPager 
       android:id="@+id/log_pager" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" /> 
</LinearLayout> 

Menu:

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:id="@+id/menu_refresh" 
      android:title="Refresh" 
      android:icon="@android:drawable/ic_delete" 
      android:showAsAction="ifRoom|withText" /> 
</menu> 

menu Akcja jest wypełniana: http://i.stack.imgur.com/QFMDd.png

menu Akcja nie jest zaludniony: http://i.stack.imgur.com/sH5Pp.png

+0

Zgadzam się z Solarnz wydaje się, że nie ma żadnego oczywistego rozwiązania. Stworzyłem aplikację [demonstrator] (https://github.com/sngariapper/page-flipper-race-condition/), która umożliwia niezawodne odtworzenie problemu. Ten sam problem wydaje się być [zgłoszony w ActionBarSherlock] (https://github.com/JakeWharton/ActionBarSherlock/issues/351) i podniosłem ten [problem] (http://code.google.com/p/android/issues/detail? id = 29472) w narzędziu do śledzenia błędów na Androidzie. – snodnipper

Odpowiedz

21

Należy przeczytać (przez xcolw ...)

Poprzez eksperymenty wydaje się głównej przyczyny nazywany jest invalidateOptionsMenu coraz więcej niż jeden bez przerwy na głównym wątku, aby przetworzyć w kolejce zadań. Przypuszczenie - ma to znaczenie, jeśli jakaś krytyczna część tworzenia menu została odroczona za pośrednictwem postu, pozostawiając pasek działania w złym stanie, dopóki nie zostanie uruchomiony.

Istnieje kilka miejsc to może się zdarzyć, że nie są oczywiste:

  1. zawijające viewPager.setCurrentItem wiele razy na tej samej pozycji

  2. wywołującego viewPager.setCurrentItem w onCreate aktywności. setCurrentItem powoduje uruchomienie menu invalidate opcja, która następuje bezpośrednio w menu opcji aktywności za utratę

Obejścia Znalazłem dla każdego

  1. Straży wywołaniu viewPager.setCurrentItem

    if (viewPager.getCurrentItem() != position) 
        viewPager.setCurrentItem(position); 
    
  2. odroczyć wezwanie do viewPager.setCurrentItem w onCreate

    public void onCreate(...) { 
        ... 
        view.post(new Runnable() { 
         public void run() { 
          // guarded viewPager.setCurrentItem 
         } 
        } 
    } 
    

po tych menu opcji zmiany wewnątrz widoku pager wydaje się działać zgodnie z oczekiwaniami. Mam nadzieję, że ktoś może rzucić więcej światła na to.

źródłohttp://code.google.com/p/android/issues/detail?id=29472

+0

Doskonały. Dzięki. –

+0

Pls, dostarcz kompletnego snajpa, jak używać tego z viewpager bez kart, nie jest dla mnie jasne. Dzięki. –

+0

To nie zadziałało dla mnie. mViewPager.post (nowa Runnable() { @Override public void run() { mViewPager.setAdapter (nowa FragPagerAdapter (getSupportFragmentManager(), MainActivity.this));! if (mViewPager.getCurrentItem() = 1) { mViewPager.setCurrentItem (1); } } }); –

8

Odpowiedź jest prosta, aby nie korzystać z menu w ciągu fragmentów w ViewPager. Jeśli potrzebujesz użyć menu w fragmentach, sugeruję ładowanie menu za pomocą metody onCreateOptionsMenu w aktywności nadrzędnej. Oczywiście musisz mieć możliwość określenia, które menu ma być wyświetlane.

Udało mi się to osiągnąć za pomocą refleksji klasowej. Należy również użyć metody invalidateptionsMenu przy każdym przełączaniu stron. Będziesz potrzebował OnPageChangeListener do wywołania tego, gdy ViewPager zmieni strony.

+0

Czy możesz podzielić się tym kodem? –

0

Najpierw utwórz metodę w klasie sub FragmentPagerAdapter uzyskać bieżącego fragmentu

public SherlockFragment getFragment() { 
    return currentFragment; 
} 

     @Override 
public void onTabSelected(final Tab tab, FragmentTransaction ft) { 

    ((SherlockFragmentActivity) mContext).invalidateOptionsMenu(); 
    Fragment f = ((SherlockFragmentActivity) mContext) 
      .getSupportFragmentManager().findFragmentByTag(
        makeFragmentName(tab.getPosition())); 

    currentFragment=(SherlockFragment) f; 
} 

Teraz przesłonić poniżej metod Main Actvity

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    if (mTabsAdapter.getPositionOfTabSelected() != 0) { 
     menu.add("Read").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     menu.add("Write").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     menu.add("Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     menu.add("Factory data reset").setShowAsAction(
       MenuItem.SHOW_AS_ACTION_IF_ROOM); 
    } 

    return super.onCreateOptionsMenu(menu); 
} 

obecnie nazywamy onOptionItemSelected z działania do fragmentu

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    mTabsAdapter.getFragment().onOptionsItemSelected(item); 
    return super.onOptionsItemSelected(item); 
} 
3

Też miałem ten sam problem. W moim przypadku mam jedną czynność z viewpagerem, która zawiera dwa fragmenty, każdy fragment nadyma własne menu akcji, ale nie wyświetla się menu akcji fragmentu.

Zobacz Kod adapter pager

public class ScreensAdapter extends FragmentPagerAdapter { 

    public TrackerScreensAdapter(Context context, FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public int getCount() { 
     return 2; 
    } 

    public Fragment getItem(int position) { 
     Fragment fragment = null; 
     switch (position){ 
      case 0: 
       fragment = new Fragment1(); 
       break; 
      case 1: 
       fragment = new Fragment2(); 
       break; 
     } 
     return fragment; 
    } 

} 

Aktywność na tworzenie

screensAdapter = new ScreensAdapter(this, getFragmentManager()); 
    viewPager.setAdapter(screensAdapter); 

ten sposób mój viewPager ma dwóch fragmentów, każdy fragment ognia własną zadanie onActivityCreated, uzyskać dane i wyciągnąć jego układ oparty na uzyskane dane. Również każdy fragment ma onCreateOptionsMenu

@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
    setHasOptionsMenu(true); 
    MyTask task = new MyTask(); 
    task.setTaskListener(this); 
    task.execute(); 


} 

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    inflater.inflate(R.menu.fragment_menu, menu); 
} 

spędził wiele razy, aby rozwiązać ten problem i dowiedzieć się, dlaczego fragment menu nie widać. Wszystko, co było potrzeba

screenAdapter = new ScreenAdapter(this, getFragmentManager()); 
    viewPager.post(new Runnable() { 
     public void run() { 
      viewPager.setAdapter(screenAdapter); 
     } 
    }); 
+0

Dzięki! ustawienie adaptera w runnable rozwiązało go dla mnie –

0

I rozwiązać bardzo podobny problem, w którym ikony paska akcji przydzielonych przez fragment wewnątrz ViewPager znikały OnPause(). Pojawią się ponownie, gdy Fragment pojawi się ponownie, a użytkownik przesunie się w lewo lub w prawo, ale nie od razu. Rozwiązaniem było wywołanie metody notifyDataSetChanged() na PagerAdapter w metodzie onResume() fragmentu.

@Override 
public void onResume() { 
    mPagerAdapter.notifyDataSetChanged(); 
} 
0

miałem ten problem z rzeczami Action barze, podczas gdy używałem HorizontalScrollView pokazać zaczepy ale zmieniłem do PagerTitleStrip i problem został rozwiązany.

Być może ta informacja może pomóc komuś innemu.

0

W moim przypadku wyśledziłem główną przyczynę problemu, co do którego uważam, że jest błędem w FragmentStatePagerAdapter, który wywołuje Fragment#setMenuVisibility na wartość false i niepoprawnie ustawia go ponownie na true, gdy przywraca stan.

Obejścia:

  1. Zastosowanie FragmentPagerAdapter zamiast FragmentStatePagerAdapter

  2. Jeśli trzeba użyć FragmentStatePagerAdapter, w adapter podklasy override setPrimaryItem tak:

    @Override 
    public void setPrimaryItem(ViewGroup container, int position, Object object) { 
        super.setPrimaryItem(container, position, object); 
    
        //This is a workaround for a bug in FragmentStatePagerAdapter 
        Fragment currentItem = getItem(position); 
        if (currentItem != null) { 
         currentItem.setMenuVisibility(true); 
         currentItem.setUserVisibleHint(true); 
        } 
    } 
    
+0

Żadne z tych podejść nie działa. – Proverbio

Powiązane problemy