ViewPager 및 프래그먼트 — 프래그먼트의 상태를 저장하는 올바른 방법은 무엇입니까?
조각은 UI 논리를 일부 모듈로 분리하는 데 매우 좋은 것 같습니다. 그러나 ViewPager
수명주기 와 함께 여전히 안개 낀다. 따라서 전문가의 생각이 절실히 필요합니다!
편집하다
아래 바보 같은 솔루션을 참조하십시오 ;-)
범위
주요 활동에는 ViewPager
조각이 있습니다. 이러한 조각은 다른 (서브) 활동에 대해 약간 다른 논리를 구현할 수 있으므로 조각의 데이터는 활동 내부의 콜백 인터페이스를 통해 채워집니다. 그리고 첫 출시에서 모든 것이 잘 작동하지만! ...
문제
액티비티가 다시 생성되면 (예 : 방향 변경 등) ViewPager
의 조각도 생성됩니다. 코드 (아래에서 찾을 수 있음)는 활동이 생성 될 때마다 ViewPager
조각과 동일한 새 조각 어댑터 를 만들려고 시도 하지만 (문제 일 수도 있음) FragmentManager는 이미 이러한 조각을 어딘가에 어디에 있습니까 (?) 이를위한 레크리에이션 메커니즘을 시작합니다. 따라서 레크리에이션 메커니즘은 Activity의 구현 된 메소드를 통해 데이터를 시작하기위한 콜백 인터페이스 호출과 함께 "오래된"프래그먼트의 onAttach, onCreateView 등을 호출합니다. 그러나이 메소드는 Activity의 onCreate 메소드를 통해 작성된 새로 작성된 단편을 가리 킵니다.
발행물
어쩌면 나는 잘못된 패턴을 사용하고 있지만 Android 3 Pro 서적에도 그다지 많지 않습니다. 그래서, 제발 , 나에게 원 - 투 펀치를주고 그것을 올바른 방법을 수행하는 방법을 지적한다. 많은 감사합니다!
암호
주요 활동
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);
}
BasePagerActivity 일명 도우미
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... */
}
해결책
바보 같은 해결책은 putFragment를 사용하여 onSaveInstanceState (호스트 활동)의 조각을 저장하고 getFragment를 통해 onCreate 안에 넣는 것입니다. 그러나 여전히 일이 그렇게 작동해서는 안된다는 이상한 느낌이 있습니다 ... 아래 코드를 참조하십시오 :
@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
FragmentManager에 프래그먼트를 추가 할 때 프래그먼트가 배치 될 특정 위치를 기반으로 특수 태그를 사용합니다. FragmentPagerAdapter.getItem(int position)
해당 위치의 조각이 존재하지 않는 경우에만 호출됩니다. 회전 한 후 Android는이 특정 위치에 대한 조각을 이미 생성 / 저장했음을 확인하므로 FragmentManager.findFragmentByTag()
새 위치를 만드는 대신 로 다시 연결을 시도합니다 . 이 모든 것은 사용할 때 무료로 제공 FragmentPagerAdapter
되므로 getItem(int)
메소드 내부에 조각 초기화 코드를 사용하는 것이 일반적 입니다.
우리가를 사용하지 않더라도 FragmentPagerAdapter
, 매번 새로운 조각을 만드는 것은 좋은 생각이 아닙니다 Activity.onCreate(Bundle)
. 알다시피 FragmentManager에 조각이 추가되면 회전 후 조각이 다시 만들어지고 다시 추가 할 필요가 없습니다. 프래그먼트로 작업 할 때 오류가 발생하는 일반적인 원인입니다.
프래그먼트로 작업 할 때 일반적인 방법은 다음과 같습니다.
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)에 의해 제어됩니다 . 이로 인해 어댑터 외부의 프래그먼트에서 직접 호출하는 메소드는 유효하지 않을 수도 있습니다.
간단히 이야기하자면 putFragment
나중에 참조를 얻는 데 사용할 수있는 솔루션 은 그리 미친 것이 아니며 어쨌든 조각을 사용하는 일반적인 방법과는 다릅니다. 프래그먼트가 사용자가 아닌 어댑터에 의해 추가되기 때문에 그렇지 않으면 참조를 얻기가 어렵습니다. offscreenPageLimit
원하는 조각에 의존하기 때문에 원하는 조각을 항상로드 할 수있을만큼 충분히 높은지 확인하십시오 . 이것은 ViewPager의 게으른 로딩 기능을 우회하지만 응용 프로그램에서 원하는 것 같습니다.
또 다른 방법은 FragmentPageAdapter.instantiateItem(View, int)
수퍼 호출에서 리턴 된 프래그먼트에 대한 참조를 리턴하기 전에이를 대체 하고 저장하는 것입니다 (이미 존재하는 경우 프래그먼트를 찾는 논리가 있음).
전체 그림을 보려면 FragmentPagerAdapter (짧은) 및 ViewPager (긴) 의 소스를 살펴보십시오 .
나는 해결책을 제공하기 위해 원하는에 팽창 antonyt
의 멋진 대답 및 재정의 언급 FragmentPageAdapter.instantiateItem(View, int)
생성에 대한 참조를 저장 Fragments
하면 나중에 작업을 할 수 있습니다. 이것은 또한 작동합니다 FragmentStatePagerAdapter
; 자세한 내용은 참고 사항을 참조하십시오.
다음 은의 내부 집합에 의존하지 않는에 Fragments
의해 반환되는 참조를 얻는 간단한 예입니다 . 핵심은 에서 대신 에 참조 를 재정의 하고 저장하는 것 입니다 .FragmentPagerAdapter
tags
Fragments
instantiateItem()
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
클래스 멤버 변수 / 참조 대신 작업하는 것을 선호하는 경우 동일한 방식으로 세트를 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 소스 코드 에서 알 수 있듯이 조각을 사용하여 생성 된 태그 아래 에 FragmentPagerAdapter
상점에서 관리합니다 FragmentManager
.
String tag="android:switcher:" + viewId + ":" + index;
(가) viewId
는 IS 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로 슬라이딩하고 있지만 (onConfigurationChange) 회전하면 OnCreate가 다시 호출되므로 새 페이지가 생깁니다. 그러나 회전하기 전에 만들어진 모든 페이지를 계속 참조하고 싶습니다.
문제 -내가 만드는 각 조각에 대한 고유 식별자가 없으므로 참조 / 참조하는 유일한 방법은 회전 / 구성 변경 후 복원 할 배열에 참조를 저장하는 것입니다.
해결 방법 -핵심 개념은 활동 (조각을 표시)이 기존 조각에 대한 참조 배열을 관리하도록하는 것이 었습니다.이 활동은 onSaveInstanceState의 번들을 활용할 수 있기 때문입니다.
public class MainActivity extends FragmentActivity
따라서이 활동 내에서 공개 페이지를 추적 할 개인 회원을 선언합니다.
private List<Fragment> retainedPages = new ArrayList<Fragment>();
onSaveInstanceState가 호출되어 onCreate에서 복원 될 때마다 업데이트됩니다.
@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
동일한 구성 (MainActivity에서 위에 표시된대로)
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
그런 다음이를 onCreate에 추가하면 조각이 파괴되지 않습니다.
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
? 표준 호출기 어댑터 중 하나를 사용해야합니다. FragmentPagerAdapter
또는 FragmentStatePagerAdapter
더 이상 필요하지 않은 조각을 ViewPager
보존하거나 (이전) 상태를 저장하고 (후자) 다시 작성하려는 경우에 따라 또는 다시 필요했습니다.
사용 ViewPager
을 위한 샘플 코드는 여기 에서 찾을 수 있습니다.
FragmentManager
프레임 워크에서 상태를 저장하고 호출기가 작성한 모든 활성 조각을 복원 하기 때문에 활동 인스턴스에서보기 호출기의 조각 관리가 약간 복잡 하다는 것은 사실입니다. 이 모든 것은 실제로 초기화 할 때 어댑터가 복원 된 조각과 다시 연결해야한다는 것을 의미합니다. 코드를 FragmentPagerAdapter
보거나 FragmentStatePagerAdapter
수행 방법을 확인할 수 있습니다 .
FragmentStatePagerAdapter와 관련하여 문제가있는 경우 조각의 상태를 올바르게 복원하지 못하는 경우 ... 예 : FragmentStatePagerAdapter가 상태에서 복원하는 대신 FragmentStatePagerAdapter에서 새 조각을 생성하는 중입니다 ...
전화하기 ViewPager.setOffscreenPageLimit()
전에 반드시 전화하십시오ViewPager.setAdapeter(fragmentStatePagerAdapter)
호출하면 ViewPager.setOffscreenPageLimit()
... ViewPager는 즉시 어댑터를 찾고 조각을 가져 오려고 시도합니다. 이는 ViewPager가 savedInstanceState에서 Fragments를 복원 할 수 있기 전에 발생할 수 있습니다 (따라서 SavedInstanceState에서 새 초기화되어 다시 초기화 할 수없는 새 Fragments를 작성 함).
나는이 간단하고 우아한 솔루션을 생각해 냈습니다. 액티비티가 프래그먼트 작성을 담당하고 어댑터가이를 제공한다고 가정합니다.
이것은 어댑터의 코드입니다 ( 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();
}
}
이 스레드의 모든 문제는 "오래된"조각에 대한 참조를 얻는 것이므로 Activity의 onCreate에서이 코드를 사용합니다.
if (savedInstanceState!=null) {
if (getSupportFragmentManager().getFragments()!=null) {
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
mFragments.add(fragment);
}
}
}
물론 조각이 특정 클래스의 인스턴스인지 확인하는 등 필요한 경우이 코드를 추가로 미세 조정할 수 있습니다.
방향 변경 후 프래그먼트를 가져 오려면 .getTag ()를 사용해야합니다.
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager)
조금 더 처리하려면 viewPagerId 및 FragmentClass를 사용하여 모든 위치에서 조각을 가져 오기 위해 PageAdapter에 대한 자체 ArrayList를 작성했습니다.
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()));
viewPager에 추가하십시오.
mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages);
myViewPager.setAdapter(mAdapter);
이 후 오리엔테이션 후에 클래스를 사용하여 올바른 조각을 변경할 수 있습니다.
WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager()
.findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class));
더하다:
@SuppressLint("ValidFragment")
수업 전에.
다음과 같이 작동하지 않습니다.
@SuppressLint({ "ValidFragment", "HandlerLeak" })
'Programming' 카테고리의 다른 글
기본적으로 MongoDB 셸에서 예쁜 인쇄 (0) | 2020.02.13 |
---|---|
JavaScript에서 두 날짜의 차이가 있습니까? (0) | 2020.02.13 |
목록 또는 데이터 프레임의 요소에 액세스하기위한 대괄호 []와 이중 대괄호 [[]]의 차이점 (0) | 2020.02.13 |
git가 추적중인 파일 목록을 표시하도록하려면 어떻게해야합니까? (0) | 2020.02.13 |
JIT (Just-In-Time) 컴파일러의 기능은 무엇입니까? (0) | 2020.02.13 |