programing

View Pager를 동적으로 업데이트하시겠습니까?

css3 2023. 9. 12. 20:10

View Pager를 동적으로 업데이트하시겠습니까?

ViewPager에서 내용을 업데이트할 수 없습니다.

FragmentPagerAdapter 클래스에서 항목() 인스턴스화 및 getItem() 메서드의 올바른 사용 방법은 무엇입니까?

getItem()만 사용하여 조각을 인스턴스화하고 반환했습니다.

@Override
public Fragment getItem(int position) {
    return new MyFragment(context, paramters);
}

잘 됐어요.내용을 바꿀 수 없다는 것만 빼면요.

그래서 이걸 찾았습니다.View 호출기 어댑터가 View를 업데이트하지 않음

"내 접근 방식은 인스턴스화된 보기에서 setTag() 메서드를 사용하는 것입니다."

이제 Item()을 인스턴스화하여 이를 실행하고자 합니다.그러나 반환해야 할 내용(종류는 Object)과 getItem(int 포지션)의 관계를 알 수 없습니다.

참고문헌을 읽었습니다.

  • 공개 추상 조각 getItem(위치)

    지정된 위치와 연관된 Fragment를 반환합니다.

  • 공용 개체 인스턴스화항목 (ViewGroup 컨테이너, int위치)

    지정된 위치에 대한 페이지를 만듭니다.어댑터는 여기에 제공된 컨테이너에 뷰를 추가할 책임이 있지만, 이 작업은 업데이트 완료(ViewGroup)에서 반환될 때까지만 수행되어야 합니다.매개변수

    containing View. position 인스턴스화할 페이지 위치를 지정합니다.

    돌아온다

    새 페이지를 나타내는 Object를 반환합니다.보기일 필요는 없지만 페이지의 다른 컨테이너일 수도 있습니다.

아직도 잘 모르겠어요

제 코드는 여기 있습니다.지원 패키지 v4를 사용하고 있습니다.

호출기 테스트 보기

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);
    }
}

마이 프래그먼트 어댑터

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;
    }
}

마이 프래그먼트

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.cg

FragmentPagerAdapter 는 FragmentPagerAdapter <FragmentStatePagerAdapter>만 .getItem()요 ㅜㅜinstantiateItem()조금이라도. 더instantiateItem()-destroyItem()-isViewFromObject() 더 PagerAdapter를 하는 데 수준 인터페이스입니다.getItem()인터페이스.

이 문제를 다루기 전에, 제가 분명히 말씀드려야겠습니다.

표시되는 실제 프래그먼트를 전환하려면 FragmentPagerAdapter를 피하고 FragmentStatePagerAdapter를 사용해야 합니다.

이 답변의 이전 버전은 FragmentPagerAdapter를 예제에 사용하는 실수를 범했습니다. FragmentPagerAdapter가 처음 표시된 후에는 FragmentPagerAdapter가 조각을 삭제하지 않기 때문에 작동하지 않습니다.

저는 추천하지 않습니다.setTag()그리고.findViewWithTag()당신이 링크한 게시물에 제공된 해결책.여러분이 알아낸 바와 같이, 사용하는 것은setTag()그리고.findViewWithTag()파편이 잘 안 맞아서 잘 안 맞는 거예요

올바른 해결책은 그들을 무시하는 것입니다.getItemPosition().notifyDataSetChanged() 호출, ViewPager 호출, 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가 fragment를 파괴하지 않는다고 해서 fragmentPagerAdapter에서 getItemPosition이 전혀 쓸모가 없는 것은 아닙니다.이 콜백을 사용하여 ViewPager에서 조각 순서를 변경할 수도 있습니다.그러나 Fragment Manager에서 완전히 제거되지는 않습니다.

을 돌려주는 대신 POSITION_NONEgetItemPosition()전체 보기 재생성을 실행하면 다음을 수행합니다.

//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개의 조각으로 영어 로드하는 기본값 콘텐츠조각들기본값 로드하는 fragments to content from the the load these for default 조각으로 english 조각들콘텐츠영어 to fragments forAPI서비스 하지만 여기서 문제는 내가 설정 활동에서 언어를 바꾸고 싶고 설정 활동을 마친 후에 내가 원하는 것입니다.ViewPager하는 주 을 수행합니다.가서를면의어과록을로고어를다는요서을터는n다을터는서가요ny는o를fhemotird어dsedsh서

1- 위에 언급한 것처럼 FragmentStatePagerAdapter를 사용해야 합니다.

2- on mainActivity i는 onResume을 재정의하고 다음을 수행했습니다.

if (!(mPagerAdapter == null)) {
    mPagerAdapter.notifyDataSetChanged();
}

3-나는 그보다 더 우선했습니다.getItemPosition()에서 mPagerAdapter를 합니다.POSITION_NONE.

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
}

요염한 일

는 이 오늘 배운 . 을 처음 접하는 에게 도움이 . 안드로이드를 처음 접하는 분에게 도움이 되었으면 좋겠습니다.ViewPager업데이트도 하고요.사용하고 있습니다.FragmentStatePagerAdapterAPI 레벨 17에서 현재 단 2개의 프래그먼트를 가지고 있습니다.틀린 부분이 있을 것 같은데 고쳐주세요, 감사합니다.enter image description here

  1. 직렬화된 데이터를 메모리에 로드해야 합니다.이것은 a를 사용하여 할 수 있습니다.CursorLoader/AsyncTask/Thread. 자동으로 로드되는지 여부는 코드에 따라 달라집니다.는을 CursorLoader관찰자가 , 된 가 에 으로 됩니다 됩니다 으로 에 된 가 .

  2. 를 하고 난 viewpager.setAdapter(pageradapter), getCount()조각을 만들기 위해 끊임없이 호출됩니다.로드되고 ,가고면,면o가afsg,,getCount()0을 반환할 수 있으므로 표시된 데이터가 없는 경우 더미 조각을 생성할 필요가 없습니다.

  3. 된 후 는 가 과 하지 으로 을 된 가 가 하지 으로 된 가 을 getCount()0이므로 0제터를록할다수된로다수할yes직det록제oranl00e를dgetCount(), 그런 다음 어댑터에 전화합니다.notifyDataSetChanged().ViewPager메모리의 데이터에 의해 프래그먼트(처음 두 프래그먼트만)를 생성하기 시작합니다.하기 전에 하는 거예요.notifyDataSetChanged()반환됩니다.그다음에.ViewPager당신이 필요로 하는 적당한 조각들을 가지고 있습니다.

  4. 데이터베이스와 메모리의 데이터가 둘 다 업데이트된 경우(write through), 또는 메모리의 데이터만 업데이트된 경우(write back), 또는 데이터베이스의 데이터만 업데이트된 경우.데이터가 데이터베이스에서 메모리로 자동으로 로드되지 않는 경우(위에서 언급한 바와 같이),ViewPager그리고 호출기 어댑터는 메모리에 저장된 데이터만 처리합니다.

  5. 따라서 메모리의 데이터가 업데이트되면 어댑터의 데이터를 호출하기만 하면 됩니다.notifyDataSetChanged()생성되었기 의 . . 가 되었기 에 의 의 에 가 되었기 onItemPosition()입니다 앞에 됩니다.notifyDataSetChanged()돌아온다.작업을 수행할 필요가 없습니다.getItemPosition()업데이트됩니다. 그런 다음 데이터가 업데이트됩니다.

해보세요 destroyDrawingCache()간wpwr서음에n 다음에 ViewPager에서notifyDataSetChanged()자네 코드대로

이 문제를 극복하기 위해 위의 모든 해결책들을 시도하는 동안, 그리고 이 문제를 해결하기 위해 그리고 모두 실패했던 이것과 이것과 이것과 이것과 같은 다른 비슷한 문제들에 많은 해결책들을 시도하는 동안, 몇 시간 동안 좌절을 겪은 후에, 저는 이 문제를 해결하기 위해 그리고 그것을 만들기 위해 모두 실패했습니다.ViewPagere를 파괴하다Fragment를 .pager으로와 Fragment했습니다. 다음과 같이 문제를 해결했습니다.

1)메이드 더ViewPagerFragmentPagerAdapter다음과 같이

 public class myPagerAdapter extends FragmentPagerAdapter {

2)에 대한 항목 만들기ViewPager저를 하고 있는titlee.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 제내기한스에y한to에 저장합니다.class다음과 같이

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mPagerItems = pagerItems;
}

4)메소드를 다시 설정합니다.adapter이전의 데이터를 모두 삭제하여 새로운 데이터를 사용한 데이터fragmentfragmentManager가 직접적으로으로를 .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어댑터를 새 데이터로 다시 초기화하지 마십시오. 설정해새터정정터et를hesetPagerItems다음과 같은 새로운 데이터를 사용합니다.

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) {}

}

Bill Phillips에서 제공한 솔루션을 제 요구에 맞게 약간 수정했습니다.

private class PagerAdapter extends FragmentStatePagerAdapter{
    Bundle oBundle;
    FragmentManager oFragmentManager;
    ArrayList<Fragment> oPooledFragments;

public PagerAdapter(FragmentManager fm) {
    super(fm);
    oFragmentManager=fm;

    }
@Override
public int getItemPosition(Object object) {

    Fragment oFragment=(Fragment)object;
    oPooledFragments=new ArrayList<>(oFragmentManager.getFragments());
    if(oPooledFragments.contains(oFragment))
        return POSITION_NONE;
    else
        return POSITION_UNCHANGED;
    } 
}

그렇게 해서getItemPosition()POSITION_NONE재는만만에ehyrsyeen는재hFragmentManagergetItemPosition합니다. (참고:FragmentStatePagere.ViewPager관련된 것은 액티비티가 아닌 프래그먼트에 포함됨)

저도 비슷한 문제가 있었지만 기존 솔루션(하드코드 태그 이름 등)을 신뢰하고 싶지 않아 M-WaJeEh의 솔루션을 제게 적합하게 만들 수 없었습니다.해결책은 다음과 같습니다.

getItem에 생성된 fragment를 배열로 계속 참조합니다.이 기능은 구성 변경 또는 메모리 부족 등으로 인해 작업이 파괴되지 않는 한(-->) 작업으로 돌아올 때 '가동'하지 않고 프래그먼트가 마지막 상태로 돌아갑니다.항목이 다시 호출되고 있으므로 배열을 업데이트하지 않습니다.

이 문제를 방지하기 위해 InstantizeItem(ViewGroup, int)을 구현하고 배열을 다음과 같이 업데이트했습니다.

        @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object o = super.instantiateItem(container, position);
        if(o instanceof FragmentX){
            myFragments[0] = (FragmentX)o;
        }else if(o instanceof FragmentY){
            myFragments[1] = (FragmentY)o;
        }else if(o instanceof FragmentZ){
            myFragments[2] = (FragmentZ)o;
        }
        return o;
    }

그래서 한편으로는 제게 맞는 해결책을 찾아서 여러분들과 공유하고 싶어서 기쁘지만, 다른 사람이 비슷한 시도를 했는지, 또 그렇게 해서는 안 될 이유가 있는지 묻고 싶었습니다.지금까지는 내게 아주 좋은 일이지만...

저는 같은 문제를 살아왔고 너무 많이 검색했습니다.스택 오버플로우나 구글을 통한 답변은 제 문제에 대한 해결책이 아니었습니다.내 문제는 쉬웠어요.목록이 있는데 이 목록을 보기 호출기와 함께 보여줍니다.목록 머리글에 새 요소를 추가하고 보기 페이지를 새로 고치면 아무것도 변경되지 않습니다.제 최종 해결책은 누구나 쉽게 사용할 수 있었습니다.목록에 새 요소가 추가되고 목록을 새로 고치려고 할 때.먼저 viewpager 어댑터를 null로 설정한 다음 어댑터를 다시 만들고 i를 viewpager로 설정합니다.

myVPager.setAdapter(null);
myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(),newList);
myVPager.setAdapter(myFragmentAdapter);

어댑터가 FragmentStatePagerAdapter를 확장해야 합니다.

업데이트할 때 EventBus 라이브러리를 사용합니다.FragmentViewPager. 논리는 EventBus how do의 문서처럼 간단합니다.제어할 필요가 없습니다.FragmentPagerAdapter 있습니다코드는 여기 있습니다.

1: 이벤트 정의

업데이트할 메시지를 정의합니다.

public class UpdateCountEvent {
    public final int count;

    public UpdateCountEvent(int count) {
        this.count = count;
    }
}

2.가입자 준비

업데이트가 필요한 Fragment에 아래 코드를 작성합니다.

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);  
    super.onStop();
}

public void onEvent(UpdateCountEvent event) {//get update message
    Toast.makeText(getActivity(), event.count, Toast.LENGTH_SHORT).show();
}

3.사후행사

에 에 .Activity아니면 다른Fragment 변수를야는우우는ohse개해야 .

//input update message
EventBus.getDefault().post(new UpdateCountEvent(count));

여러 가지 접근법을 시도해 보았지만 문제를 해결해 주는 방법은 없었습니다.아래는 제가 여러분이 제공한 솔루션을 혼합하여 해결하는 방법입니다.여러분 감사합니다.

class PagerAdapter extends FragmentPagerAdapter {

    public boolean flag_refresh=false;

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int page) {
        FragmentsMain f;
        f=new FragmentsMain();
        f.page=page;
        return f;
    }

    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public int getItemPosition(Object item) {
        int page= ((FragmentsMain)item).page;

        if (page == 0 && flag_refresh) {
            flag_refresh=false;
            return POSITION_NONE;
        } else {
            return super.getItemPosition(item);
        }
    }

    @Override
    public void destroyItem(View container, int position, Object object) {

        ((ViewPager) container).removeView((View) object);
    }
}

Resume() 후 0페이지만 새로 고치고 싶습니다.

 adapter=new PagerAdapter(getSupportFragmentManager());
 pager.setAdapter(adapter);

@Override
protected void onResume() {
    super.onResume();

    if (adapter!=null) {
        adapter.flag_refresh=true;
        adapter.notifyDataSetChanged();
    }
}

나의 FragmentsMain에는 공용 정수 "페이지"가 있는데, 내가 새로고침하고 싶은 페이지인지 알려줄 수 있습니다.

public class FragmentsMain extends Fragment {

private Cursor cursor;
private static Context context;
public int page=-1;

나는 당에 늦었다는 것을 압니다.했습니다에 했습니다.TabLayout#setupWithViewPager(myViewPager);에 바로 FragmentPagerAdapter#notifyDataSetChanged();

FragmentStatePagerAdapter를 사용하려면 https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=37990 을 확인하십시오.FragmentStatePagerAdapter에는 사용 사례에 문제가 발생하거나 발생하지 않을 수 있는 문제가 있습니다.

또한, 링크 역시 해결책이 거의 없습니다.당신의 요구에 맞는 것은 거의 없습니다.

이것은 누군가에게 도움이 될 수도 있습니다. 제 경우에는 새로운 페이지를 삽입할 때 호출기가 기존 조각의 위치를 두 번 요청했지만 새 항목의 위치를 요청하지 않아 잘못된 동작과 데이터가 표시되지 않습니다.

  1. FragmentStatePagerAdapter용 소스를 복사합니다(기간이 지난 후 업데이트되지 않은 것 같습니다).

  2. 알림 DataSetChanged() 재정의

    @Override
    public void notifyDataSetChanged() {
        mFragments.clear();
        super.notifyDataSetChanged();
    }
    
  3. 충돌을 방지하기 위해 항목()을 삭제하기 위해 제정신 검사를 추가합니다.

    if (position < mFragments.size()) {
        mFragments.set(position, null);
    }
    

@Bill Phillips One의 정보를 통합한 구현 방법은 데이터가 변경된 경우를 제외하고 대부분의 시간에 프래그먼트 캐싱을 받습니다.간단하며, 잘 작동하는 것 같습니다.

My Fragment StatePagerAdapter.java

private boolean mIsUpdating = false;
public void setIsUpdating(boolean mIsUpdating) {
        this.mIsUpdating = mIsUpdating;
    }


@Override
public int getItemPosition(@NonNull Object object) {

    if (mIsUpdating) {
        return POSITION_NONE;
    }
    else {
        return super.getItemPosition(object);
    }
}

My Activity.java

mAdapter.setIsUpdating(true);
mAdapter.notifyDataSetChanged();
mAdapter.setIsUpdating(false);

을 해서.ViewPager2그리고.FragmentStateAdapter:

데이터를 동적으로 업데이트하는 것은 다음과 같이 지원됩니다.ViewPager2.

문서에는 이 작업을 수행하는 방법에 대한 중요한 참고 사항이 있습니다.

: DiffUtil유틸리티 클래스는 ID로 항목을 식별하는 것에 의존합니다.ViewPager2를 사용하여 가변 컬렉션을 페이지화하는 경우 및 .(mine 강조)를 재정의해야 합니다.

에 기반을 둔ViewPager2 문서화 및 Android의 Github 샘플 프로젝트에는 다음과 같은 몇 가지 단계가 필요합니다.

  1. FragmentStateAdapter를 재정의합니다.를다음다를:음edesgetItemCount,createFragment,getItemId,그리고.containsItem (참고:FragmentStatePagerAdapter다에서 .ViewPager2)

  2. 에 어댑터를 합니다.ViewPager2

  3. 를 로ViewPager2와 함께DiffUtil 음요)음요할DiffUtil볼 수 ), 에서와 에서와 )


예:

private val items: List<Int>
    get() = viewModel.items
private val viewPager: ViewPager2 = binding.viewPager

private val adapter = object : FragmentStateAdapter(this@Fragment) {
    override fun getItemCount() = items.size
    override fun createFragment(position: Int): Fragment = MyFragment()
    override fun getItemId(position: Int): Long = items[position].id
    override fun containsItem(itemId: Long): Boolean = items.any { it.id == itemId }
}
viewPager.adapter = adapter
    
private fun onDataChanged() {
    DiffUtil
        .calculateDiff(object : DiffUtil.Callback() {
            override fun getOldListSize(): Int = viewPager.adapter.itemCount
            override fun getNewListSize(): Int = viewModel.items.size
            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
                viewPager.adapter?.getItemId(oldItemPosition) == viewModel.items[newItemPosition].id

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
                areItemsTheSame(oldItemPosition, newItemPosition)
        }, false)
        .dispatchUpdatesTo(viewPager.adapter!!)
}

이 솔루션이 모든 사람에게 효과가 있는 것은 아니지만, 제 경우에는 제 ViewPager에 있는 모든 Fragment가 다른 클래스이며, 한 번에 하나만 존재합니다.

이와 같은 제약 조건으로 이 솔루션은 안전하며 생산에 사용해도 무방합니다.

private void updateFragment(Item item) {

    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    for (Fragment fragment : fragments) {

        if (fragment instanceof MyItemFragment && fragment.isVisible()) {
            ((MyItemFragment) fragment).update(item);
        }

    }
}

같은 프래그먼트의 버전이 여러 개인 경우, 이와 동일한 전략을 사용하여 해당 프래그먼트에 메서드를 호출하여 업데이트할 프래그먼트인지 여부를 확인할 수 있습니다.

위의 모든 답변과 다른 여러 게시물을 살펴보았지만 여전히 나에게 맞는 것을 찾을 수 없었습니다(다양한 조각 유형과 함께 동적으로 탭을 추가하고 제거).).FWIW를 따르는 접근 방식이 저에게 효과적이었습니다(다른 사람이 같은 문제를 가지고 있는 경우).

public class MyFragmentStatePageAdapter extends FragmentStatePagerAdapter {
    private static final String TAB1_TITLE = "Tab 1";
    private static final String TAB2_TITLE = "Tab 2";
    private static final String TAB3_TITLE = "Tab 3";

    private ArrayList<String> titles = new ArrayList<>();
    private Map<Fragment, Integer> fragmentPositions = new HashMap<>();


    public MyFragmentStatePageAdapter(FragmentManager fm) {
        super(fm);
    }


    public void update(boolean showTab1, boolean showTab2, boolean showTab3) {
        titles.clear();

        if (showTab1) {
            titles.add(TAB1_TITLE);
        }
        if (showTab2) {
            titles.add(TAB2_TITLE);
        }
        if (showTab3) {
            titles.add(TAB3_TITLE);
        }
        notifyDataSetChanged();
    }


    @Override
    public int getCount() {
        return titles.size();
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = null;

        String tabName = titles.get(position);
        if (tabName.equals(TAB1_TITLE)) { 
            fragment =  Tab1Fragment.newInstance();
        } else if (tabName.equals(TAB2_TITLE)) {
            fragment =  Tab2Fragment.newInstance();
        } else if (tabName.equals(TAB3_TITLE)) {
            fragment =  Tab3Fragmen.newInstance();
        } 

        ((BaseFragment)fragment).setTitle(tabName);
        fragmentPositions.put(fragment, position);
        return fragment;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles.get(position);
    }

    @Override
    public int getItemPosition(Object item) {
        BaseFragment fragment = (BaseFragment)item;
        String title = fragment.getTitle();
        int position = titles.indexOf(title);

        Integer fragmentPosition = fragmentPositions.get(item);
        if (fragmentPosition != null && position == fragmentPosition) {
            return POSITION_UNCHANGED;
        } else {
            return POSITION_NONE;
        }
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
        fragmentPositions.remove(object);
    }
}

인덱스 기반으로 fragment를 다시 만들거나 다시 로드하려면 FragmentPagerAdapter 대신 FragmentStatePagerAdapter를 사용하십시오. 예를 들어 FirstFragment 이외의 fragment를 다시 로드하려면 다음과 같이 인스턴스(instance) 및 반환 위치를 확인할 수 있습니다.

 public int getItemPosition(Object item) {
    if(item instanceof FirstFragment){
       return 0;
    }
    return POSITION_NONE;
 }

즉각적인 변화가 필요합니다.항목의 mFragments 요소 getItemPosition.

    if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);

        if (f != null) {
            int newPosition = getItemPosition(f);
            if (newPosition == POSITION_UNCHANGED) {
                return f;
            } else if (newPosition == POSITION_NONE) {
                mFragments.set(position, null);
            } else {
                mFragments.set(newPosition, f);
            }
        }
    }

AndroidX AndroidX FragmentStatePagerAdapter.java:mFragments를 호출해도 의 요소 위치는 변경되지 않습니다.

출처 : https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java

예: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt

이 프로젝트를 실행하여 작업 방법을 확인할 수 있습니다.https://github.com/cuichanghao/infivt

언급URL : https://stackoverflow.com/questions/10849552/update-viewpager-dynamically