ViewPager 및 fragments - fragment의 상태를 저장하는 올바른 방법은 무엇입니까?
모듈로 하는 데 것 같습니다.fragments UI는 UI를 사용할 수 . 하만그와함께지와 함께.ViewPager
그것의 라이프사이클은 여전히 나에게 안개입니다.그래서 구루의 생각이 절실히 필요합니다!
편집
아래의 멍청한 해결책 보기 ;-)
범위
주요 활동은 다음과 같습니다.ViewPager
이러한 다른 할 수 fragment의 를 통해 채워집니다.이러한 단편은 다른 (하위) 활동에 대해 약간 다른 논리를 구현할 수 있으므로, 단편의 데이터는 활동 내부의 콜백 인터페이스를 통해 채워집니다.첫 번째 발사에서는 모든 것이 잘 작동합니다. 하지만!
문제
방향 변경 시ViewPager
아래에서 찾을 수 ) 코드는 때마다 활동을 위해 노력한다고 말합니다.ViewPager
fragments와 하지만 fragments fragments, , Manager, fragments에 대한 재생 메커니즘을 시작합니다.따라서 레크리에이션 메커니즘은 활동의 구현된 메서드를 통해 데이터를 시작하기 위해 내 콜백 인터페이스 호출과 함께 첨부, CreateView 등에 있는 "오래된" 조각을 호출합니다.그러나 이 메서드는 Activity의 onCreate 메서드를 통해 새로 생성된 조각을 가리킵니다.
쟁점.
제가 잘못된 패턴을 사용하고 있는지도 모르지만 안드로이드 3 프로 책에도 별로 없습니다.그러니 원투 펀치를 주시고 올바른 방법을 알려주세요.감사합니다!
코드
기본 활동
public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener {
private MessagesFragment mMessagesFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
Logger.d("Dash onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_container);
new DefaultToolbar(this);
// create fragments to use
mMessagesFragment = new MessagesFragment();
mStreamsFragment = new StreamsFragment();
// set titles and fragments for view pager
Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>();
screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment());
screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment);
// instantiate view pager via adapter
mPager = (ViewPager) findViewById(R.id.viewpager_pager);
mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
// set title indicator
TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles);
indicator.setViewPager(mPager, 1);
}
/* set of fragments callback interface implementations */
@Override
public void onMessageInitialisation() {
Logger.d("Dash onMessageInitialisation");
if (mMessagesFragment != null)
mMessagesFragment.loadLastMessages();
}
@Override
public void onMessageSelected(Message selectedMessage) {
Intent intent = new Intent(this, StreamActivity.class);
intent.putExtra(Message.class.getName(), selectedMessage);
startActivity(intent);
}
BasePager
public class BasePagerActivity extends FragmentActivity {
BasePagerAdapter mPagerAdapter;
ViewPager mPager;
}
어댑터
public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider {
private Map<String, Fragment> mScreens;
public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) {
super(fm);
this.mScreens = screenMap;
}
@Override
public Fragment getItem(int position) {
return mScreens.values().toArray(new Fragment[mScreens.size()])[position];
}
@Override
public int getCount() {
return mScreens.size();
}
@Override
public String getTitle(int position) {
return mScreens.keySet().toArray(new String[mScreens.size()])[position];
}
// hack. we don't want to destroy our fragments and re-initiate them after
@Override
public void destroyItem(View container, int position, Object object) {
// TODO Auto-generated method stub
}
}
파편
public class MessagesFragment extends ListFragment {
private boolean mIsLastMessages;
private List<Message> mMessagesList;
private MessageArrayAdapter mAdapter;
private LoadMessagesTask mLoadMessagesTask;
private OnMessageListActionListener mListener;
// define callback interface
public interface OnMessageListActionListener {
public void onMessageInitialisation();
public void onMessageSelected(Message selectedMessage);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// setting callback
mListener = (OnMessageListActionListener) activity;
mIsLastMessages = activity instanceof DashboardActivity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
inflater.inflate(R.layout.fragment_listview, container);
mProgressView = inflater.inflate(R.layout.listrow_progress, null);
mEmptyView = inflater.inflate(R.layout.fragment_nodata, null);
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// instantiate loading task
mLoadMessagesTask = new LoadMessagesTask();
// instantiate list of messages
mMessagesList = new ArrayList<Message>();
mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList);
setListAdapter(mAdapter);
}
@Override
public void onResume() {
mListener.onMessageInitialisation();
super.onResume();
}
public void onListItemClick(ListView l, View v, int position, long id) {
Message selectedMessage = (Message) getListAdapter().getItem(position);
mListener.onMessageSelected(selectedMessage);
super.onListItemClick(l, v, position, id);
}
/* public methods to load messages from host acitivity, etc... */
}
해결책
멍청한 솔루션은 futFragment를 사용하여 내부의 fragment를 SaveInstanceState(호스트 활동의)에 저장하고 getFragment를 통해 Create(생성)에 fragment를 내부로 가져오는 것입니다.하지만 아직도 이상한 느낌이 들어요. 일이 그렇게 되어서는 안 된다는...아래 코드 참조:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager()
.putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment);
}
protected void onCreate(Bundle savedInstanceState) {
Logger.d("Dash onCreate");
super.onCreate(savedInstanceState);
...
// create fragments to use
if (savedInstanceState != null) {
mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment(
savedInstanceState, MessagesFragment.class.getName());
StreamsFragment.class.getName());
}
if (mMessagesFragment == null)
mMessagesFragment = new MessagesFragment();
...
}
때.FragmentPagerAdapter
Fragment Manager에 fragment를 추가합니다. fragment는 fragment가 배치될 특정 위치에 따라 특수 태그를 사용합니다. FragmentPagerAdapter.getItem(int position)
해당 위치의 조각이 없는 경우에만 호출됩니다.회전한 후 Android는 이 특정 위치에 대한 조각을 이미 생성/저장했음을 알게 되므로 단순히 다시 연결하려고 합니다.FragmentManager.findFragmentByTag()
새로 생성하는 대신.이 모든 것은 사용 시 무료로 제공됩니다.FragmentPagerAdapter
를 fragment initialization 를 fragment interial로 하는 것이 일반적인 이유입니다.getItem(int)
방법.
우리가 사용하지 않았더라도FragmentPagerAdapter
매번 새로운 조각을 만드는 것은 좋은 생각이 아닙니다.Activity.onCreate(Bundle)
Fragment Manager에 fragment가 추가되면 fragment가 회전한 후 다시 생성되므로 다시 추가할 필요가 없습니다.이렇게 하면 fragment 작업 시 오류가 발생하는 일반적인 원인이 됩니다.
조각 작업 시 일반적인 접근 방식은 다음과 같습니다.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
CustomFragment fragment;
if (savedInstanceState != null) {
fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag");
} else {
fragment = new CustomFragment();
getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit();
}
...
}
를 사용하는 경우FragmentPagerAdapter
관리를 할 필요가 없습니다."라고 말합니다.단, 기적으단앞뒤조프다니됩다각, ).FragmentStatePagerAdapter
). 이는 ViewPager.setOffscreenPageLimit(int)에 의해 제어됩니다.이 때문에 어댑터 외부의 fragment에 직접 호출하는 메서드는 활성화되지 않을 수 있으므로 유효하지 않습니다.
간단히 말해서, 사용할 수 있는 해결책입니다.putFragment
나중에 참조를 얻을 수 있다는 것은 그렇게 미친 것도 아니며, 어쨌든 fragment를 사용하는 일반적인 방법과 다르지 않습니다(위).사용자가 아닌 어댑터가 조각을 추가했기 때문에 참조를 얻기가 어렵습니다.꼭 확인해 주세요.offscreenPageLimit
이 값은 원하는 조각을 항상 로드할 수 있을 정도로 높습니다. 이 값은 해당 조각이 존재하는 것에 의존하기 때문입니다.이렇게 하면 ViewPager의 느린 로드 기능을 생략할 수 있지만 응용 프로그램에 대해 원하는 것처럼 보입니다.
또 다른 접근 방식은 오버라이드입니다.FragmentPageAdapter.instantiateItem(View, int)
슈퍼콜에서 반환된 fragment에 대한 참조를 저장한 후 반환합니다(fragment가 이미 존재하는 경우 fragment를 찾을 수 있는 로직이 있습니다).
전체 그림을 보려면 FragmentPagerAdapter(짧은 길이) 및 ViewPager(긴 길이)의 일부 소스를 살펴봅니다.
확장 가능한 솔루션을 제공하고 싶습니다.antonyt
의 멋진 답변과 우선순위에 대한 언급.FragmentPageAdapter.instantiateItem(View, int)
된 성된참저면에 합니다.Fragments
나중에 작업할 수 있도록 해주세요.이 작업은 다음 작업에도 사용할 수 있습니다.FragmentStatePagerAdapter
자세한 내용은 참고를 참조하십시오.
다음은 에 대한 참조를 얻는 방법에 대한 간단한 예입니다.Fragments
된환반이 했습니다.FragmentPagerAdapter
그은것니지하않습다의존내부.tags
을설한정에 .Fragments
중요한 것은 참조를 재정의하고 저장하는 것입니다.getItem()
.
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
또는 당신이 함께 일하는 것을 선호한다면.tags
변수 " " /신조refe클래버"에 대한Fragments
당신은 또한 그것을 잡을 수 있습니다.tags
에 의해 설정된.FragmentPagerAdapter
는 다음과 같은 경우에는.FragmentStatePagerAdapter
날이 저물지 않아서tags
를 할 때Fragments
.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
이 방법은 내부를 모방하는 데 의존하지 않습니다.tag
에 의해 설정된.FragmentPagerAdapter
대신 적절한 API를 사용하여 검색합니다.이런 식으로 해도 말입니다.tag
의 향후 의 변경 SupportLibrary
당신은 여전히 안전할 것입니다.
당신의 디자인에 따라 다르다는 것을 잊지 마세요.Activity
,Fragments
당신은 아직 존재할 수도 있고 존재하지 않을 수도 있으므로, 당신은 그것을 함으로써 설명해야 합니다.null
참조를 사용하기 전에 확인합니다.
또한, 만약 당신이 대신 일을 한다면,FragmentStatePagerAdapter
그러면 당신은 당신의 엄격한 언급을 유지하고 싶지 않을 것입니다.Fragments
왜냐하면 당신은 그것들 중 많은 것들을 가지고 있을 수 있고 하드 레퍼런스는 그것들을 불필요하게 기억에 간직할 것이기 때문입니다. 신대저를 합니다.Fragment
에어의언급에 있는 참고 WeakReference
표준 변수 대신 변수를 입력합니다.다음과 같이:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}
당신의 질문에 대한 다른 비교적 쉬운 해결책을 찾았습니다.
FragmentPagerAdapter 소스 코드에서 알 수 있듯이, fragments는 다음과 같이 관리됩니다.FragmentPagerAdapter
에저에 합니다.FragmentManager
다음을 사용하여 생성된 태그 아래:
String tag="android:switcher:" + viewId + ":" + index;
그viewId
는 것은입니다.container.getId()
,container
의 신의입니다.ViewPager
사례.그index
조각의 위치입니다.를 서라객를 ID 수할있다에 할 수 .outState
:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("viewpagerid" , mViewPager.getId() );
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
viewpagerid=savedInstanceState.getInt("viewpagerid", -1 );
MyFragmentPagerAdapter titleAdapter = new MyFragmentPagerAdapter (getSupportFragmentManager() , this);
mViewPager = (ViewPager) findViewById(R.id.pager);
if (viewpagerid != -1 ){
mViewPager.setId(viewpagerid);
}else{
viewpagerid=mViewPager.getId();
}
mViewPager.setAdapter(titleAdapter);
만약 당신이 이 조각과 통신하고 싶다면, 당신은 다음과 같은 것을 얻을 수 있습니다.FragmentManager
를 들어 다음과 같습니다.
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0")
저는 아마도 약간 다른 사례에 대한 대안을 제시하고 싶습니다. 왜냐하면 저의 답변에 대한 많은 검색이 저를 계속 이 스레드로 이끌었기 때문입니다.
내 경우 - 동적으로 페이지를 생성/추가하고 ViewPager로 이동하지만(구성 변경 시) 회전하면 OnCreate가 다시 호출되기 때문에 새 페이지가 나타납니다.하지만 저는 회전하기 전에 만들어진 모든 페이지를 계속 참조하고 싶습니다.
문제 - 생성하는 각 조각에 대해 고유한 식별자가 없으므로 참조할 수 있는 유일한 방법은 회전/구성 변경 후 복원할 배열에 참조를 저장하는 것이었습니다.
해결 방법 - 핵심 개념은 활동(Fragments 표시)에서 기존 Fragment에 대한 참조 배열도 관리하는 것이었습니다. 이 활동은 SaveInstanceState의 번들을 활용할 수 있기 때문입니다.
public class MainActivity extends FragmentActivity
따라서 이 활동에서 열려 있는 페이지를 추적할 개인 구성원을 선언합니다.
private List<Fragment> retainedPages = new ArrayList<Fragment>();
이는 SaveInstanceState가 호출되고 Create에서 복원될 때마다 업데이트됩니다.
@Override
protected void onSaveInstanceState(Bundle outState) {
retainedPages = _adapter.exportList();
outState.putSerializable("retainedPages", (Serializable) retainedPages);
super.onSaveInstanceState(outState);
}
일단 저장되면 검색할 수 있습니다
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
retainedPages = (List<Fragment>) savedInstanceState.getSerializable("retainedPages");
}
_mViewPager = (CustomViewPager) findViewById(R.id.viewPager);
_adapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager());
if (retainedPages.size() > 0) {
_adapter.importList(retainedPages);
}
_mViewPager.setAdapter(_adapter);
_mViewPager.setCurrentItem(_adapter.getCount()-1);
}
이것들은 주요 활동에 필요한 변경 사항들이었고, 그래서 저는 이것이 작동하기 위해 fragmentPagerAdapter 내의 구성원들과 방법들이 필요했습니다, 그래서 안에서.
public class ViewPagerAdapter extends FragmentPagerAdapter
동일한 구성(위의 주 활동에 표시됨)
private List<Fragment> _pages = new ArrayList<Fragment>();
그리고 이 동기화(위의 onSaveInstanceState에서 사용된 바와 같이)는 특히 메소드에 의해 지원됩니다.
public List<Fragment> exportList() {
return _pages;
}
public void importList(List<Fragment> savedPages) {
_pages = savedPages;
}
그리고 마지막으로 단편 수업에서
public class CustomFragment extends Fragment
이 모든 것이 작동하기 위해, 첫 번째, 두 가지 변화가 있었습니다.
public class CustomFragment extends Fragment implements Serializable
그런 다음 조각이 파괴되지 않도록 만들기에 추가합니다.
setRetainInstance(true);
저는 아직 Fragments와 Android 라이프 사이클에 대해 고민하고 있습니다. 따라서 이 방법에는 중복성/비효율성이 있을 수 있습니다.하지만 그것은 저에게 효과가 있고 저와 비슷한 사례를 가진 다른 사람들에게 도움이 되기를 바랍니다.
제 솔루션은 매우 무례하지만 효과적입니다. 보존된 데이터에서 동적으로 생성된 제 조각이기 때문에, 저는 단순히 모든 조각을 제거합니다.PageAdapter
전화하기 super.onSaveInstanceState()
활동을 만들 때 다시 작성합니다.
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("viewpagerpos", mViewPager.getCurrentItem() );
mSectionsPagerAdapter.removeAllfragments();
super.onSaveInstanceState(outState);
}
수없다니습에서 할 수 onDestroy()
그렇지 않으면 다음과 같은 예외가 발생합니다.
java.lang.IllegalStateException:
다음 이후에는 이 작업을 수행할 수 없습니다.onSaveInstanceState
페이지 어댑터의 코드는 다음과 같습니다.
public void removeAllfragments()
{
if ( mFragmentList != null ) {
for ( Fragment fragment : mFragmentList ) {
mFm.beginTransaction().remove(fragment).commit();
}
mFragmentList.clear();
notifyDataSetChanged();
}
}
하고 재현페만복저다니원합에 합니다.onCreate()
조각이 생성된 후.
if (savedInstanceState != null)
mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) );
은 입니까?BasePagerAdapter
은 표준 호출기 중 . -- " 표 호 하 사 야 합 니 다 해 용 를 준 나 중 출 어 기 댑 터 다 합 니 ▁you ▁-- ▁adapters ▁one ▁either ▁use 표 ▁pagerFragmentPagerAdapter
또는FragmentStatePagerAdapter
.ViewPager
(전자) 상태를 유지하거나 (전자) 상태를 저장하고 (전자) 필요한 경우 다시 생성합니다.
을 사용하기 위한 ViewPager
여기에서 확인할 수 있습니다.
간 입니다.FragmentManager
이 프레임워크에서는 상태를 저장하고 호출기가 만든 활성 조각을 복원합니다.이 모든 것은 초기화할 때 어댑터가 복원된 조각과 다시 연결되는지 확인해야 한다는 것을 의미합니다.를 보면 .FragmentPagerAdapter
또는FragmentStatePagerAdapter
어떻게 하는지 확인할 수 있습니다.
fragmentStatePagerAdapter에서 fragment의 상태를 제대로 복원하지 못하는 문제가 있는 경우... 즉, 새 fragment는 fragmentStatePagerAdapter에서 상태에서 복원하는 대신 생성됩니다.
꼭전세요에 전화하세요.ViewPager.setOffscreenPageLimit()
하기 ViewPager.setAdapter(fragmentStatePagerAdapter)
에 할 때ViewPager.setOffscreenPageLimit()
...ViewPager는 즉시 어댑터를 찾아 fragment를 가져옵니다.이 문제는 ViewPager가 저장된 인스턴스 상태에서 조각을 복원하기 전에 발생할 수 있습니다(따라서 새 조각이므로 저장된 인스턴스 상태에서 다시 초기화할 수 없는 새 조각을 만듭니다).
저는 이 간단하고 우아한 해결책을 생각해냈습니다.이는 활동이 Fragment를 생성하고 어댑터가 Fragment를 제공하는 것으로 가정합니다.
이것은 어댑터의 코드입니다. (여기서 이상한 것은 없습니다. 단,mFragments
활동에 의해 유지 관리되는 조각 목록입니다.)
class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public CharSequence getPageTitle(int position) {
TabFragment fragment = (TabFragment)mFragments.get(position);
return fragment.getTitle();
}
}
이 스레드의 전체 문제는 "오래된" 조각의 참조를 얻는 것이므로, 이 코드를 활동의 작성에 사용합니다.
if (savedInstanceState!=null) {
if (getSupportFragmentManager().getFragments()!=null) {
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
mFragments.add(fragment);
}
}
}
물론 필요한 경우 이 코드를 더 미세하게 조정할 수 있습니다. 예를 들어 조각이 특정 클래스의 인스턴스인지 확인하는 것이 좋습니다.
방향 변경 후 fragment를 가져오려면 .getTag()를 사용해야 합니다.
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager)
조금 더 다루기 위해 나는 페이지 어댑터에 대해 나만의 배열 목록을 작성하여 fragment를 viewPagerId로 가져오고 fragmentClass를 임의의 위치에서 가져옵니다.
public class MyPageAdapter extends FragmentPagerAdapter implements Serializable {
private final String logTAG = MyPageAdapter.class.getName() + ".";
private ArrayList<MyPageBuilder> fragmentPages;
public MyPageAdapter(FragmentManager fm, ArrayList<MyPageBuilder> fragments) {
super(fm);
fragmentPages = fragments;
}
@Override
public Fragment getItem(int position) {
return this.fragmentPages.get(position).getFragment();
}
@Override
public CharSequence getPageTitle(int position) {
return this.fragmentPages.get(position).getPageTitle();
}
@Override
public int getCount() {
return this.fragmentPages.size();
}
public int getItemPosition(Object object) {
//benötigt, damit bei notifyDataSetChanged alle Fragemnts refrehsed werden
Log.d(logTAG, object.getClass().getName());
return POSITION_NONE;
}
public Fragment getFragment(int position) {
return getItem(position);
}
public String getTag(int position, int viewPagerId) {
//getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.shares_detail_activity_viewpager + ":" + myViewPager.getCurrentItem())
return "android:switcher:" + viewPagerId + ":" + position;
}
public MyPageBuilder getPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
return new MyPageBuilder(pageTitle, icon, selectedIcon, frag);
}
public static class MyPageBuilder {
private Fragment fragment;
public Fragment getFragment() {
return fragment;
}
public void setFragment(Fragment fragment) {
this.fragment = fragment;
}
private String pageTitle;
public String getPageTitle() {
return pageTitle;
}
public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
}
private int icon;
public int getIconUnselected() {
return icon;
}
public void setIconUnselected(int iconUnselected) {
this.icon = iconUnselected;
}
private int iconSelected;
public int getIconSelected() {
return iconSelected;
}
public void setIconSelected(int iconSelected) {
this.iconSelected = iconSelected;
}
public MyPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
this.pageTitle = pageTitle;
this.icon = icon;
this.iconSelected = selectedIcon;
this.fragment = frag;
}
}
public static class MyPageArrayList extends ArrayList<MyPageBuilder> {
private final String logTAG = MyPageArrayList.class.getName() + ".";
public MyPageBuilder get(Class cls) {
// Fragment über FragmentClass holen
for (MyPageBuilder item : this) {
if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
return super.get(indexOf(item));
}
}
return null;
}
public String getTag(int viewPagerId, Class cls) {
// Tag des Fragment unabhängig vom State z.B. nach bei Orientation change
for (MyPageBuilder item : this) {
if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
return "android:switcher:" + viewPagerId + ":" + indexOf(item);
}
}
return null;
}
}
따라서 다음 조각으로 MyPageArrayList를 만듭니다.
myFragPages = new MyPageAdapter.MyPageArrayList();
myFragPages.add(new MyPageAdapter.MyPageBuilder(
getString(R.string.widget_config_data_frag),
R.drawable.ic_sd_storage_24dp,
R.drawable.ic_sd_storage_selected_24dp,
new WidgetDataFrag()));
myFragPages.add(new MyPageAdapter.MyPageBuilder(
getString(R.string.widget_config_color_frag),
R.drawable.ic_color_24dp,
R.drawable.ic_color_selected_24dp,
new WidgetColorFrag()));
myFragPages.add(new MyPageAdapter.MyPageBuilder(
getString(R.string.widget_config_textsize_frag),
R.drawable.ic_settings_widget_24dp,
R.drawable.ic_settings_selected_24dp,
new WidgetTextSizeFrag()));
페이지 보기에 추가합니다.
mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages);
myViewPager.setAdapter(mAdapter);
이 후에는 클래스를 사용하여 올바른 fragment를 변경한 후에 얻을 수 있습니다.
WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager()
.findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class));
Fragments를 직접 저장하는 대신 Fragment Manager에게 맡겨두고 Fragment를 처리해야 할 경우 Fragment Manager에서 Fragment를 찾습니다.
//make sure you have the right FragmentManager
//getSupportFragmentManager or getChildFragmentManager depending on what you are using to manage this stack of fragments
List<Fragment> fragments = fragmentManager.getFragments();
if(fragments != null) {
int count = fragments.size();
for (int x = 0; x < count; x++) {
Fragment fragment = fragments.get(x);
//check if this is the fragment we want,
//it may be some other inspection, tag etc.
if (fragment instanceof MyFragment) {
//do whatever we need to do with it
}
}
}
Fragments가 많고 검사 인스턴스 비용이 원하는 것이 아닐 수도 있지만 Fragment Manager가 Fragments를 이미 보관하고 있다는 점을 염두에 두는 것이 좋습니다.
추가:
@SuppressLint("ValidFragment")
수업 전에
다음과 같은 것을 하는 것은 효과가 없습니다.
@SuppressLint({ "ValidFragment", "HandlerLeak" })
언급URL : https://stackoverflow.com/questions/7951730/viewpager-and-fragments-whats-the-right-way-to-store-fragments-state
'programing' 카테고리의 다른 글
NULL 열에 고유 인덱스를 만드는 방법은 무엇입니까? (0) | 2023.06.04 |
---|---|
고유한 Android 장치 ID가 있습니까? (0) | 2023.06.04 |
푸시 알림에 의해 실행될 때 앱 디버깅 (0) | 2023.06.04 |
배열에서 개체를 찾으시겠습니까? (0) | 2023.06.04 |
.NET에 UI 독립적인 Point 구조가 있습니까? (0) | 2023.06.04 |