답변:
주요 답변은 프레임 워크에서 생성되는 이름에 의존합니다. 이것이 변경되면 더 이상 작동하지 않습니다.
이 솔루션에 대해 무엇을, 무시 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
심판?
getItem
때문에 회전 할 때 (이미 생성 된 조각에 대해) 다시 호출되지 않는 것을 확인했습니다 . 경우 각각의 경우에 불려 복원,이 솔루션은 사실에 더 안전하고 미래의 증거 광산 또는 허용 대답보다. 나는 이것을 직접 시도하는 것을 고려할 것이다. FragmentManager
Fragments
instantiateItem
Fragment
ViewPager에서 조각을 잡으려면 여기 및 기타 관련 SO 스레드 / 블로그에 많은 답변이 있습니다. 내가 본 사람은 모두 부서졌으며 일반적으로 아래에 나열된 두 가지 유형 중 하나에 해당하는 것 같습니다. 이처럼 현재 조각 만 잡고 싶다면 다른 유효한 솔루션 이 있습니다. 이 스레드에서 다른 대답.
사용하는 경우 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
최신 지원 libFragmentViewPager
의 소스 에서 사용자 고유의 클래스를 구성 하고 조각 태그를 생성하기 위해 내부적으로 사용되는 메소드를 변경하십시오. 아래와 같이 교체 할 수 있습니다. 이는 태그 생성이 절대 변경되지 않으며 항상 개인 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;
}
doc이 말했듯이 인덱스에 사용 된 조각을 가져 오려면 getItem이 아직 호출되지 않은 경우 FragmentPagerAdapter
결과 가 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;
}
이것은 간단한 솔루션이며 웹 어디에서나 발견되는 다른 두 가지 솔루션의 문제를 해결합니다.
instantiateItem()
아직 방문하지 않고 수명주기 이벤트 전에 방문한 프래그먼트에 액세스하려는 경우의 하나 이상의 사용 사례에서 작동한다는 것 입니다 . 내가 아는 작은 차이점이지만 내 프로그램에 미묘한 버그가 생겨서 이것을 조사하고 있습니다.
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
. 보스턴의 대답 거리는 훨씬 포괄적 인 솔루션으로,이 접근법 대신 프로젝트에서 사용합니다.
필자의 경우 위의 해결책 중 어느 것도 효과가 없었습니다.
그러나 Fragment에서 Child Fragment Manager를 사용하고 있으므로 다음이 사용되었습니다.
Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
Manager의 조각이 viewpager 항목과 일치하는 경우에만 작동합니다.
먼저 모든 조각 목록을 만들어서 처리했습니다.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();
}
그러나 그것은 내 핵 및 슬래시 접근 방식이지만 저에게 효과적이었습니다. 뒤 버튼을 누를 때 현재 표시된 조각에 관련 변경을 수행합니다.
이것은 위의 Steven의 답변을 기반으로합니다. 부모 활동에 이미 첨부 된 조각의 실제 인스턴스를 반환합니다.
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()
a의 참조 얻을 이후 단계에서 다른 방법 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;
가장 좋은 해결책은 CodePath 에서 만든 SmartFragmentStatePagerAdapter 라는 확장을 사용하는 것입니다 . 이 가이드에 따라 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()
메소드에서 조각 페이지를 추가하고 조각을 대체 할 수있는 fragmentTransaction을 사용하여 Viewpager의 태그를 전달하십시오.
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
하는WeakReference
것이 좋습니다. 그냥 옳은 일처럼 보인다 ...