回答:
主な答えは、フレームワークによって生成される名前に依存しています。それが変わると、それは機能しなくなります。
何このソリューションについて、オーバーライドinstantiateItem()
とdestroyItem()
あなたのFragment(State)PagerAdapter
:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
これは、利用可能なフラグメントを処理するときに私にはうまくいくようです。まだインスタンス化されていないフラグメントは、を呼び出すとnullを返しますgetRegisteredFragment
。しかし、私は、現在取得し、主にこれを使用してきたFragment
のアウトViewPager
:adapater.getRegisteredFragment(viewPager.getCurrentItem())
これは戻りませんnull
。
このソリューションの他の欠点は知りません。あれば教えてください。
MyPagerAdapter
ライフサイクル(つまり、回転)によって破壊された場合、何がregisterdFragments
失われますか?ウィルActivity
/ Fragment
使用してMyPagerAdapter
、それを保存する必要がありonSaveInstanceState
、その後、新しいとそれを更新する必要がFragmentManager
REF?
getItem
ので、(すでに作成されているすべてのフラグについて)回転時に再度呼び出されないことを確認しました。場合は、それぞれのときに呼び出され、復元され、その後、このソリューションは、実際にはより安全で、将来の証明鉱山や受け入れ答えより。これを自分で試すことを検討します。FragmentManager
Fragments
instantiateItem
Fragment
ViewPagerからフラグメントを取得するために、ここおよび他の関連するSOスレッド/ブログに多くの答えがあります。私が見たすべての人は壊れており、彼らは一般的に以下にリストされている2つのタイプのいずれかに分類されるようです。現在のフラグメントのみを取得したい場合は、他のいくつかの有効な解決策があります。このスレッドのこの他の回答のように。
使用FragmentPagerAdapter
する場合は、以下を参照してください。使用している場合はFragmentStatePagerAdapter
その価値を見て、これを。FragmentStateAdapterの現在のインデックスではないインデックスを取得することは、その性質上、完全に分解されてビューの外/ offScreenLimitの境界外になるほど有用ではありません。
誤り:FragmentPagerAdapter.getItem()
が呼び出されたときに追加される、フラグメントの独自の内部リストを維持する
SparseArray
またはMap
getItem
最初にページがスクロールされたとき(またはViewPager.setOffscreenPageLimit(x)
> 0の場合に取得されたとき)にのみ呼び出されるためViewPager
、ホスティングActivity
/ Fragment
が強制終了または再起動SpaseArray
された場合、カスタムFragmentPagerActivityが再作成されるときに内部が消去されますが、シーンの背後ではViewPagers内部フラグメントが再作成され、かつgetItem
ますNOTインデックスのいずれかのために呼び出されるので、インデックスからの断片を取得する能力が永遠に失われてしまいます。あなたはアウト節約を介してこれらのフラグメントの参照を復元することによってこれを説明することができますFragmentManager.getFragment()
し、 putFragment
これは厄介な私見を取得するために開始します。誤り:内部で使用されているものと一致する独自のタグIDを作成しFragmentPagerAdapter
、これを使用してページフラグメントをFragmentManager
ViewPager
ことができいつでも、またはどのOSバージョンでも変更できます。このソリューションのために再作成されたメソッドは
private static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
ViewPager.instantiateItem()
getItem()
上記と同様のアプローチですが、ライフサイクルを壊さない方法は、インデックスが作成またはアクセスされるたびに前者が呼び出されるのではinstantiateItem()
なく、フックすることですgetItem()
。この回答を見る
FragmentViewPager
最新のサポートライブラリのソースFragmentViewPager
から独自のクラスを構築し、フラグメントタグを生成するために内部で使用されるメソッドを変更します。下記のものと交換できます。これには、タグの作成が変更されず、常に危険なプライベートAPI /メソッドに依存しないことがわかっているという利点があります。
/**
* @param containerViewId the ViewPager this adapter is being supplied to
* @param id pass in getItemId(position) as this is whats used internally in this class
* @return the tag used for this pages fragment
*/
public static String makeFragmentName(int containerViewId, long id) {
return "android:switcher:" + containerViewId + ":" + id;
}
次に、ドキュメントに記載されているように、インデックスに使用されるフラグメントを取得する場合は、このメソッド(カスタムFragmentPagerAdapter
またはサブクラスに配置できます)などを呼び出すだけで、getItemがまだ呼び出されていない場合は結果がnullになる可能性があることに注意してください。つまり、そのページはまだ作成されていません。
/**
* @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
* yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
* the current positions fragment.
*/
public @Nullable Fragment getFragmentForPosition(int position)
{
String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
return fragment;
}
これはシンプルなソリューションで、ウェブ上のいたるところにある他の2つのソリューションの問題を解決します
instantiateItem()
まだアクセスされておらず、ライフサイクルイベントの前にアクセスされたフラグメントにアクセスしたい場合に、上記が1つ以上のユースケースで機能することです。私が知っている小さな違いですが、プログラムの微妙なバグにつながったので、これを調べています。
getItemId(pos)
内部FragmentStatePagerAdapter
FragmentPagerAdapterに次のメソッドを追加します。
public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return mFragmentManager.findFragmentByTag(name);
}
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
getActiveFragment(0)が機能する必要があります。
これがViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424dに実装されたソリューションです。何かが失敗した場合、適切なクラッシュログが表示されます。
別の簡単な解決策:
public class MyPagerAdapter extends FragmentPagerAdapter {
private Fragment mCurrentFragment;
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
//...
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}
setPrimaryItem()
呼ばれるように:-( ViewPager.OnPageChangeListener#onPageSelected()
私はこれにいくつかの答えがあることを知っていますが、多分これは誰かを助けるでしょう。Fragment
からを取得する必要がある場合、私は比較的単純なソリューションを使用しましたViewPager
。あなたにActivity
またはFragment
保持ViewPager
、あなたはすべてのを循環にこのコードを使用することができFragment
、それが保持しています。
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
if(viewPagerFragment != null) {
// Do something with your Fragment
// Check viewPagerFragment.isResumed() if you intend on interacting with any views.
}
}
での自分の位置がわかっている場合Fragment
はViewPager
、を呼び出すだけgetItem(knownPosition)
です。
でのの位置がわからない場合Fragment
はViewPager
、のFragments
ようなメソッドgetUniqueId()
を使用して子供にインターフェースを実装させ、それを使用してそれらを区別することができます。または、すべてFragments
を循環してクラスタイプを確認することもできます。if(viewPagerFragment instanceof FragmentClassYouWant)
!!! 編集!!!
それぞれが最初に作成される必要がgetItem
あるFragmentPagerAdapter
場合にのみによって呼び出されることを発見しFragment
ました。その後、を使用してリサイクルされているようです。このように、の多くの実装では、に新しいが作成されます。上記の方法を使用すると、これは、内のすべてのアイテムを処理するときに呼び出されるたびに新しいを作成することを意味します。このため、私が使用して、より良いアプローチを発見した各を取得するために(受け入れ答えを使用して)代わりに。これはより完全なソリューションであり、私にとってはうまく機能しています。Fragments
FragmentManager
FragmentPagerAdapter
Fragment
getItem
Fragment
getItem
FragmentPagerAdapter
FragmentManager
Fragment
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
String name = makeFragmentName(mViewPager.getId(), i);
Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
// OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
if(viewPagerFragment != null) {
// Do something with your Fragment
if (viewPagerFragment.isResumed()) {
// Interact with any views/data that must be alive
}
else {
// Flag something for update later, when this viewPagerFragment
// returns to onResume
}
}
}
そして、このメソッドが必要になります。
private static String makeFragmentName(int viewId, int position) {
return "android:switcher:" + viewId + ":" + position;
}
ViewPager
それ自体がこれらのタグを設定します。このソリューションは、の「隠された」命名規則を知っていることに依存しているため、脆弱ViewPager
です。Streets of Bostonの答えは、はるかに包括的なソリューションであり、(このアプローチではなく)プロジェクトで使用しています。
最初にすべてのフラグメントのリストを作成して処理しました(List<Fragment> fragments;
)の次にそれらをページャーに追加して、現在表示されているフラグメントをより簡単に処理できるようにしました。
そう:
@Override
onCreate(){
//initialise the list of fragments
fragments = new Vector<Fragment>();
//fill up the list with out fragments
fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));
//Set up the pager
pager = (ViewPager)findViewById(R.id.pager);
pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
pager.setOffscreenPageLimit(4);
}
したがって、これは次のように呼び出すことができます:
public Fragment getFragment(ViewPager pager){
Fragment theFragment = fragments.get(pager.getCurrentItem());
return theFragment;
}
それで、正しいフラグメントにある場合にのみ実行されるifステートメントでそれをチャックできます
Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
//then you can do whatever with the fragment
theFrag.costomFunction();
}
しかし、それは私のハックとスラッシュのアプローチにすぎませんが、私にとってはうまくいきました。[戻る]ボタンが押されたときに、現在表示されているフラグメントに関連する変更を行うために使用しています。
これは上記のスティーブンの答えに基づいています。これは、親アクティビティに既にアタッチされているフラグメントの実際のインスタンスを返します。
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
if(viewPagerFragment != null && viewPagerFragment.isAdded()) {
if (viewPagerFragment instanceof FragmentOne){
FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
if (oneFragment != null){
oneFragment.update(); // your custom method
}
} else if (viewPagerFragment instanceof FragmentTwo){
FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;
if (twoFragment != null){
twoFragment.update(); // your custom method
}
}
}
}
これを行う簡単でクリーンな方法が見つかりませんでした。ただし、ViewPagerウィジェットは、フラグメントをホストする別のViewGroupにすぎません。ViewPagerには、直接の子としてこれらのフラグメントがあります。したがって、(。getChildCount()および.getChildAt()を使用して)それらを反復処理し、探しているフラグメントインスタンスが現在ViewPagerにロードされているかどうかを確認し、その参照を取得できます。たとえば、いくつかの静的な一意のIDフィールドを使用して、フラグメントを区別することができます。
ViewPagerは、ListViewのような仮想化コンテナーであるため、探しているフラグメントをロードしていない可能性があることに注意してください。
FragmentPagerAdapterはフラグメントのファクトリです。まだメモリ内にある場合、その位置に基づいてフラグメントを見つけるには、これを使用します。
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
v4サポートAPIのサンプルコード。
あなたがいない通話に必要なgetItem()
の参照を取得するために、後の段階で、または他のいくつかの方法でFragment
ホストされている内部をViewPager
。内部のデータを更新したい場合はFragment
、このアプローチを使用してください:ViewPagerを動的に更新しますか?
重要なのは、内部に新しいデータを設定してAdaper
を呼び出すことです。notifyDataSetChanged()
これにより、が呼び出されgetItemPosition()
、自分の参照が渡さFragment
れ、更新する機会が与えられます。他のすべての方法では、自分自身または他のハックへの参照を維持する必要がありますが、これは良い解決策ではありません。
@Override
public int getItemPosition(Object object) {
if (object instanceof UpdateableFragment) {
((UpdateableFragment) object).update(xyzData);
}
//don't return POSITION_NONE, avoid fragment recreation.
return super.getItemPosition(object);
}
getItemPosition()
アダプタのメソッドです。直接呼び出すことはありません。あなたはあなたのアダプターのリファレンスを持っているので、あなたはあなたのsのリファレンスを渡すことによってあなたのアダプターadapter.notifyDataSetChanged()
を呼び出しgetItemPosition()
ますFragment
。あなたはここにアクションで完全な実装を見ることができますstackoverflow.com/questions/19891828/...
Fragment
が、参照を取得する方法は議論の余地があります。他のソリューションは、すべてのフラグメントが自分自身を再作成するのFragmentManager
と同様の文字列を使用する"android:switcher:"+id
か、それから 戻ることで参照を取得します。POSITION_NONE
getItemosition()
FragmentPagerAdapter
ViewPagerアダプタークラスに拡張する必要があります。
あなたが使用する場合、あなたはFragmentStatePagerAdapter
それFragment
によってあなたを見つけることができませんID
public static String makeFragmentName(int viewPagerId, int index) {
return "android:switcher:" + viewPagerId + ":" + index;
}
この方法の使い方:-
Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;
最善の解決策は、SmartFragmentStatePagerAdapterと呼ばれる、CodePathで作成した拡張機能を使用することです。そのガイドに従って、これにより、ViewPagerからフラグメントと現在選択されているフラグメントを簡単に取得できるようになります。また、アダプター内に埋め込まれたフラグメントのメモリーをより適切に管理します。
最も簡単で最も簡潔な方法。のすべてのフラグメントViewPager
が異なるクラスのものである場合、次のようにしてそれらを取得および区別できます。
public class MyActivity extends Activity
{
@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if (fragment.getClass() == MyFragment.class) {
mMyFragment = (MyFragment) fragment;
}
}
}
/values/integers.xmlに整数のリソースIDを作成します
<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>
次に、PagerAdapter getItem関数で:
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = FragmentOne.newInstance();
mViewPager.setTag(R.integer.page1,fragment);
}
else if (position == 1) {
fragment = FragmentTwo.newInstance();
mViewPager.setTag(R.integer.page2,fragment);
} else if (position == 2) {
fragment = FragmentThree.newInstance();
mViewPager.setTag(R.integer.page3,fragment);
}
return fragment;
}
次に、アクティビティでこの関数を記述して、フラグメント参照を取得します。
private Fragment getFragmentByPosition(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = (Fragment) mViewPager.getTag(R.integer.page1);
break;
case 1:
fragment = (Fragment) mViewPager.getTag(R.integer.page2);
break;
case 2:
fragment = (Fragment) mViewPager.getTag(R.integer.page3);
break;
}
return fragment;
}
上記の関数を呼び出してフラグメント参照を取得し、カスタムフラグメントにキャストします。
Fragment fragment = getFragmentByPosition(position);
if (fragment != null) {
FragmentOne fragmentOne = (FragmentOne) fragment;
}
フラグメントマネージャーでフラグメントを反復する簡単な方法。public static PlaceholderFragment newInstance(int sectionNumber)に配置されたセクション位置引数を持つviewpagerを見つけます 。
public PlaceholderFragment getFragmentByPosition(Integer pos){
for(Fragment f:getChildFragmentManager().getFragments()){
if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
return (PlaceholderFragment) f;
}
}
return null;
}
断片的に
public int getArgument(){
return mPage;
{
public void update(){
}
FragmentActivity
List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
if((f instanceof PageFragment)&&(!f.isDetached())){
PageFragment pf = (PageFragment)f;
if(pf.getArgument()==pager.getCurrentItem())pf.update();
}
}
TabLayoutにはFragmentの複数のタブがあります。フラグメントのインデックスを使用して、タグによってフラグメントを見つけることができます。
例のために。Fragment1のインデックスは0であるため、findFragmentByTag()
メソッドで、追加できるフラグメントトランザクションを使用してViewpager.afterのタグを渡し、フラグメントを置き換えます。
String tag = "android:switcher:" + R.id.viewPager + ":" + 0;
Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);
FragmentStatePagerAdapter
私が解決策に資金を提供するアダプターについてわかりました:
あなたのFragmentActivityで:
ActionBar mActionBar = getSupportActionBar();
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));
viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);
そして、クラスFragmentActivityにメソッドを作成します-そのメソッドがあなたのFragmentへのアクセスを提供するので、あなたはそれにあなたが望むフラグメントの位置を与える必要があるだけです:
public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}
あなたのアダプターで:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private final ActionBar actionBar;
private final FragmentManager fragmentManager;
public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}
@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}
@Override
public int getCount() {
return this.actionBar.getTabCount();
}
@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}
private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}
}
Fragment yourFragment = yourviewpageradapter.getItem(int index);
index
fragment1
最初に追加したようにアダプターのフラグメントの場所なので、fragment1
パスindex
は0として取得し、残りは同様に残ります。
Fragment
にWeakReference
あなたがごみ収集されてから破壊されたフラグメントを防ぐことはできません保証しますか?ちょうど正しいことのように思われます...