ViewPager에서 컨텐츠를 업데이트 할 수 없습니다.
FragmentPagerAdapter 클래스에서 instantiateItem () 및 getItem () 메소드의 올바른 사용법은 무엇입니까?
getItem () 만 사용하여 조각을 인스턴스화하고 반환했습니다.
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
이것은 잘 작동했습니다. 내용을 변경할 수 없다는 점만 빼면
그래서 이것을 찾았습니다 : ViewPager PagerAdapter가 View를 업데이트하지 않습니다
“제 접근법은 instantiateItem () 메소드의 인스턴스화 된 뷰에 대해 setTag () 메소드를 사용하는 것입니다.”
이제 instantiateItem ()을 구현하고 싶습니다. 그러나 무엇을 반환 해야하는지 (유형은 Object) 모르겠으며 getItem (int position)과의 관계는 무엇입니까?
나는 참조를 읽었다 :
공개 추상 조각 getItem (int position)
지정된 위치와 관련된 조각을 반환합니다.
공용 객체 instantiateItem (ViewGroup 컨테이너, int 위치)
주어진 위치에 대한 페이지를 작성하십시오. 어댑터는 여기에 제공된 컨테이너에보기를 추가해야하지만 finishUpdate (ViewGroup)에서 리턴 될 때만 수행해야합니다. 매개 변수
컨테이너 페이지가 표시 될 포함보기입니다. position 인스턴스화 할 페이지 위치.
보고
새 페이지를 나타내는 Object를 리턴합니다. 이것은 뷰일 필요는 없지만 페이지의 다른 컨테이너 일 수 있습니다.
그러나 나는 여전히 그것을 얻지 못한다.
여기 내 코드가 있습니다. 지원 패키지 v4를 사용하고 있습니다.
ViewPagerTest
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
MyFragmentAdapter
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
MyFragment
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
비슷한 문제가있는 사람도 있습니다
.http : //www.mail-archive.com/android-developers@googlegroups.com/msg200477.html
답변
FragmentPagerAdapter 또는 FragmentStatePagerAdapter를 사용할 때는 전적으로 getItem()
만지거나 전혀 손대지 않는 것이 가장 좋습니다 instantiateItem()
. instantiateItem()
– destroyItem()
– isViewFromObject()
PagerAdapter에 대한 인터페이스는 FragmentPagerAdapter의 사용이 훨씬 간단 구현하는 낮은 수준의 인터페이스 getItem()
인터페이스를.
이것에 들어가기 전에, 나는 명확히해야합니다
표시되는 실제 조각을 끄려면 FragmentPagerAdapter를 피하고 FragmentStatePagerAdapter를 사용해야합니다.
이 답변의 이전 버전은 FragmentPagerAdapter를 사용하는 실수를 예로 들었습니다. FragmentPagerAdapter는 처음 표시 된 후에는 FragmentPagerAdapter가 조각을 파괴하지 않기 때문에 작동하지 않습니다.
나는 당신이 링크 한 게시물에 제공된 setTag()
및 findViewWithTag()
해결 방법을 권장하지 않습니다 . 발견했듯이 조각을 사용 setTag()
하고 findViewWithTag()
작동하지 않으므로 일치하지 않습니다.
올바른 해결책은 재정의하는 것 getItemPosition()
입니다. 경우 notifyDataSetChanged()
라고, ViewPager 통화 getItemPosition()
가 다른 위치로 이동하거나 제거 할 필요가 있는지 여부를 확인하기 위해 어댑터에있는 모든 항목에.
기본적 getItemPosition()
으로을 반환합니다 POSITION_UNCHANGED
. 즉, “이 개체는 아무 곳에 나 있으면 파괴하거나 제거하지 마십시오.” 반환 POSITION_NONE
대신에, 말을하지 않습니다에 의해 수정에게 문제를 “이 개체는 더 이상 내가 그것을 제거, 표시하고있어 항목입니다.” 따라서 어댑터의 모든 단일 항목을 제거하고 다시 만드는 효과가 있습니다.
이것은 완전히 합법적 인 수정입니다! 이 수정 사항은 notifyDataSetChanged가보기 재활용없이 일반 어댑터처럼 작동하도록합니다. 이 수정 프로그램을 구현하고 성능이 만족 스럽다면 경쟁을 시작한 것입니다. 작업이 완료되었습니다.
더 나은 성능이 필요하면 더 멋진 getItemPosition()
구현을 사용할 수 있습니다 . 다음은 문자열 목록에서 조각을 만드는 호출기의 예입니다.
ViewPager pager = /* get my ViewPager */;
// assume this actually has stuff in it
final ArrayList<String> titles = new ArrayList<String>();
FragmentManager fm = getSupportFragmentManager();
pager.setAdapter(new FragmentStatePagerAdapter(fm) {
public int getCount() {
return titles.size();
}
public Fragment getItem(int position) {
MyFragment fragment = new MyFragment();
fragment.setTitle(titles.get(position));
return fragment;
}
public int getItemPosition(Object item) {
MyFragment fragment = (MyFragment)item;
String title = fragment.getTitle();
int position = titles.indexOf(title);
if (position >= 0) {
return position;
} else {
return POSITION_NONE;
}
}
});
이 구현에서는 새 제목을 표시하는 조각 만 표시됩니다. 여전히 목록에있는 제목을 표시하는 조각은 대신 목록의 새 위치로 이동하고 더 이상 목록에없는 제목을 가진 조각은 완전히 삭제됩니다.
프래그먼트를 다시 만들지 않았지만 업데이트해야 할 경우 어떻게해야합니까? 살아있는 조각에 대한 업데이트는 조각 자체에 의해 가장 잘 처리됩니다. 그것은 결국 조각을 갖는 이점입니다. 그것은 자체 컨트롤러입니다. 조각은의 다른 객체에 리스너 또는 관찰자를 추가 한 onCreate()
다음에서 제거 onDestroy()
하여 업데이트 자체를 관리 할 수 있습니다. getItem()
ListView 또는 다른 AdapterView 유형의 어댑터에서와 같이 모든 업데이트 코드를 내부에 넣을 필요는 없습니다 .
마지막으로 FragmentPagerAdapter가 프래그먼트를 파괴하지 않는다고해서 FragmentPagerAdapter에서 getItemPosition이 완전히 쓸모 없다는 의미는 아닙니다. 이 콜백을 사용하여 ViewPager에서 프래그먼트를 재정렬 할 수 있습니다. 그러나 FragmentManager에서 완전히 제거하지는 않습니다.
답변
전체보기 재생 POSITION_NONE
에서 돌아와서 재생하는 대신 다음을 getItemPosition()
수행하십시오.
//call this method to update fragments in ViewPager dynamically
public void update(UpdateData xyzData) {
this.updateData = xyzData;
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object) {
if (object instanceof UpdateableFragment) {
((UpdateableFragment) object).update(updateData);
}
//don't return POSITION_NONE, avoid fragment recreation.
return super.getItemPosition(object);
}
조각은 UpdateableFragment
인터페이스 를 구현해야합니다 .
public class SomeFragment extends Fragment implements
UpdateableFragment{
@Override
public void update(UpdateData xyzData) {
// this method will be called for every fragment in viewpager
// so check if update is for this fragment
if(forMe(xyzData)) {
// do whatever you want to update your UI
}
}
}
그리고 인터페이스 :
public interface UpdateableFragment {
public void update(UpdateData xyzData);
}
데이터 클래스 :
public class UpdateData {
//whatever you want here
}
답변
내가 ViewPager
7 조각으로 가질 때 이전에 직면했던 것과 같은 문제에 여전히 직면하는 사람들을 위해 . 이 조각의 기본값은 API
서비스 에서 영어 내용을로드하는 문제이지만 여기서는 설정 활동에서 언어를 변경하고 설정 활동을 마친 후에 ViewPager
주요 활동에서 사용자의 언어 선택과 일치하도록 조각을 새로 고치고 싶습니다 . 사용자가 아랍어를 선택하면 아랍어 콘텐츠가 처음부터 작업 한 것
1- 위에서 언급 한대로 FragmentStatePagerAdapter를 사용해야합니다.
mainActivity의 2- onResume을 무시하고 다음을 수행했습니다.
if (!(mPagerAdapter == null)) {
mPagerAdapter.notifyDataSetChanged();
}
3-i getItemPosition()
는 mPagerAdapter에서 재정 의하여 반환 POSITION_NONE
합니다.
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
매력처럼 작동합니다
답변
나는이 문제에 직면하여 오늘 그것을 마침내 해결 했으므로 내가 배운 것을 적어두고 Android에 익숙하지 않은 사람에게 도움이되기를 바랍니다 ViewPager
. FragmentStatePagerAdapter
API 레벨 17에서 사용 중이며 현재 2 개의 조각 만 있습니다. 정확하지 않은 것이 있다고 생각합니다. 감사합니다.
-
직렬화 된 데이터는 메모리에로드되어야합니다. 이것은
CursorLoader
/AsyncTask
/를 사용하여 수행 할 수 있습니다Thread
. 자동로드 여부는 코드에 따라 다릅니다. 를 사용하는 경우CursorLoader
등록 된 데이터 옵저버가 있으므로 자동으로로드됩니다. -
을 호출 한 후에
viewpager.setAdapter(pageradapter)
는 어댑터getCount()
가 지속적으로 호출되어 프래그먼트를 빌드합니다. 따라서 데이터가로드되면getCount()
0을 반환 할 수 있으므로 데이터가 표시되지 않도록 더미 조각을 만들 필요가 없습니다. -
데이터가로드 된
getCount()
후에도 여전히 0이므로 어댑터가 프래그먼트를 자동으로 빌드하지 않으므로 실제로로드 된 데이터 번호를로 설정getCount()
하여 어댑터의를 호출 할 수 있습니다notifyDataSetChanged()
.ViewPager
메모리의 데이터로 조각 (처음 두 조각 만)을 만들기 시작하십시오.notifyDataSetChanged()
반환 되기 전에 완료되었습니다 . 그런 다음ViewPager
필요한 조각이 있습니다. -
데이터베이스와 메모리의 데이터가 모두 업데이트 (쓰기)하거나 메모리의 데이터 만 업데이트 (다시 쓰기)되거나 데이터베이스의 데이터 만 업데이트되는 경우 마지막 두 경우에 데이터가 데이터베이스에서 메모리로 자동로드되지 않는 경우 (위에서 언급 한 바와 같이).
ViewPager
및 호출기 어댑터는 메모리에 데이터를 처리. -
따라서 메모리의 데이터가 업데이트되면 어댑터를 호출하기 만하면됩니다
notifyDataSetChanged()
. 프래그먼트가 이미 작성되었으므로 어댑터가 리턴onItemPosition()
되기 전에 호출됩니다notifyDataSetChanged()
. 에서 수행 할 작업이 없습니다getItemPosition()
. 그런 다음 데이터가 업데이트됩니다.
답변
코드 destroyDrawingCache()
에서 ViewPager를 사용해보십시오 notifyDataSetChanged()
.
답변
좌절의 시간이 문제를 극복하기 위해 위의 모든 솔루션을 시도 또한 같은 다른 유사한 문제에 많은 솔루션을하는 동안 후 이 , 이 그리고 이 모두가이 문제를 해결하고 만들기 위해 나와 함께 실패하는 ViewPager
기존의 파괴 Fragment
와 채우기 pager
로 새로운 Fragment
s. 다음과 같이 문제를 해결했습니다.
1) 만들기 기능 ViewPager
확장에 클래스를 FragmentPagerAdapter
다음과 같은 :
public class myPagerAdapter extends FragmentPagerAdapter {
2) 에 대한 항목을 작성 ViewPager
가게가 title
와를 fragment
다음과 같은 :
public class PagerItem {
private String mTitle;
private Fragment mFragment;
public PagerItem(String mTitle, Fragment mFragment) {
this.mTitle = mTitle;
this.mFragment = mFragment;
}
public String getTitle() {
return mTitle;
}
public Fragment getFragment() {
return mFragment;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public void setFragment(Fragment mFragment) {
this.mFragment = mFragment;
}
}
3) 인스턴스 생성자 를 다음과 같이 ViewPager
내 FragmentManager
인스턴스에 저장하십시오 class
.
private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;
public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
super(fragmentManager);
mFragmentManager = fragmentManager;
mPagerItems = pagerItems;
}
4) 다음과 같이 새 목록에서 새 항목을 다시 설정 하기 위해 직접 adapter
이전 항목 fragment
을 모두 삭제하여 새 데이터로 데이터 를 재설정하는 방법을 작성하십시오 .fragmentManager
adapter
fragment
public void setPagerItems(ArrayList<PagerItem> pagerItems) {
if (mPagerItems != null)
for (int i = 0; i < mPagerItems.size(); i++) {
mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
}
mPagerItems = pagerItems;
}
5) 컨테이너에서 Activity
또는 Fragment
새 데이터로 어댑터를 다시 초기화하지 마십시오. setPagerItems
다음과 같이 새 데이터로 메소드 를 통해 새 데이터를 설정하십시오 .
ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));
mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();
도움이 되길 바랍니다.
답변
어떤 이유로 든 대답이 나를 위해 일하지 않았으므로 fragmentStatePagerAdapter에서 super를 호출하지 않고 restoreState 메서드를 재정의해야했습니다. 암호:
private class MyAdapter extends FragmentStatePagerAdapter {
// [Rest of implementation]
@Override
public void restoreState(Parcelable state, ClassLoader loader) {}
}