Cập nhật ViewPager một cách linh hoạt?


316

Tôi không thể cập nhật nội dung trong ViewPager.

Cách sử dụng chính xác của các phương thức InstantiateItem () và getItem () trong lớp FragmentPagerAd CHƯƠNG là gì?

Tôi đã chỉ sử dụng getItem () để khởi tạo và trả lại các đoạn của mình:

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

Điều này làm việc tốt. Ngoại trừ tôi không thể thay đổi nội dung.

Vì vậy, tôi đã tìm thấy điều này: ViewPager PagerAdOG không cập nhật View

"Cách tiếp cận của tôi là sử dụng phương thức setTag () cho bất kỳ chế độ xem tức thời nào trong phương thức InstantiateItem ()"

Bây giờ tôi muốn triển khai InstantiateItem () để làm điều đó. Nhưng tôi không biết mình phải trả lại cái gì (loại là Object) và mối quan hệ với getItem (vị trí int) là gì?

Tôi đọc tài liệu tham khảo :

  • công cộng trừu tượng Fragment getItem (vị trí int)

    Trả lại các mảnh được liên kết với một vị trí được chỉ định.

  • đối tượng công khai tức thìItem (thùng chứa Viewgroup, vị trí int)

    Tạo trang cho vị trí nhất định. Bộ điều hợp có trách nhiệm thêm chế độ xem vào vùng chứa được cung cấp ở đây, mặc dù nó chỉ phải đảm bảo việc này được thực hiện vào thời điểm nó trả về từ finishUpdate (Viewgroup). Thông số

    thùng chứa Chế độ xem chứa trong đó trang sẽ được hiển thị. vị trí Vị trí trang sẽ được khởi tạo.

    Trả về

    Trả về một đối tượng đại diện cho trang mới. Đây không cần phải là Chế độ xem, nhưng có thể là một số vùng chứa khác của trang.

nhưng tôi vẫn không hiểu

Đây là mã của tôi. Tôi đang sử dụng gói hỗ trợ 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);
    }
}

MyFragmentAd CHƯƠNG

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

Đây cũng là một người có vấn đề tương tự, không có câu trả lời http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html


Để hiểu rõ hơn về các thành phần liên quan, có thể giúp đọc hướng dẫn của tôi về ViewPager được gắn thẻ với lịch sử điều hướng trở lại riêng biệt. Nó đi kèm với một ví dụ hoạt động trên GitHub và các tài nguyên bổ sung: Medium.com/@nilan/ Kẻ
marktani

có một số vấn đề stackoverflow.com/questions/40149039/...
albert

Bạn có thể kiểm tra ví dụ này trong GitHub . Tôi hy vọng ví dụ này giúp bạn.
Cabezas

Giải pháp đơn giản tốt: stackoverflow.com/a/35450575/2162226
Gene Bo

Google gần đây đã giới thiệu ViewPager2 giúp đơn giản hóa các bản cập nhật Fragment / View động. Bạn có thể thấy các ví dụ trên github.com/googlesamples/android-viewpager2 hoặc câu trả lời này trên stackoverflow.com/a/57393414/1333448
Yves Delerm

Câu trả lời:


605

Khi sử dụng FragmentPagerAd CHƯƠNG hoặc FragmentStatePagerAdRAM, cách tốt nhất là chỉ xử lý getItem()và không chạm instantiateItem()vào tất cả. Các instantiateItem()- destroyItem()- isViewFromObject()giao diện trên PagerAdapter là một giao diện cấp thấp hơn sử dụng FragmentPagerAdapter để thực hiện đơn giản hơn nhiều getItem()giao diện.

Trước khi đi vào điều này, tôi nên làm rõ rằng

nếu bạn muốn tắt các đoạn thực tế đang được hiển thị, bạn cần tránh FragmentPagerAd CHƯƠNG và sử dụng FragmentStatePagerAd CHƯƠNG.

Một phiên bản trước của câu trả lời này đã mắc lỗi sử dụng FragmentPagerAd CHƯƠNG làm ví dụ - điều đó sẽ không hiệu quả vì FragmentPagerAd CHƯƠNG không bao giờ phá hủy một đoạn sau khi nó được hiển thị lần đầu tiên.

Tôi không đề xuất setTag()findViewWithTag()cách giải quyết được cung cấp trong bài đăng bạn liên kết. Như bạn đã phát hiện ra, sử dụng setTag()findViewWithTag()không hoạt động với các mảnh vỡ, vì vậy nó không phải là một kết hợp tốt.

Giải pháp đúng là ghi đè getItemPosition(). Khi notifyDataSetChanged()được gọi, ViewPager gọi getItemPosition()tất cả các mục trong bộ điều hợp của nó để xem liệu chúng có cần được di chuyển đến một vị trí khác hoặc loại bỏ.

Theo mặc định, getItemPosition()trả về POSITION_UNCHANGED, có nghĩa là, "Đối tượng này vẫn ổn ở nơi đó, không phá hủy hoặc xóa nó." Trả về POSITION_NONEkhắc phục sự cố bằng cách thay vào đó nói: "Đối tượng này không còn là mục tôi đang hiển thị, hãy xóa nó." Vì vậy, nó có tác dụng loại bỏ và tạo lại mỗi mục trong bộ điều hợp của bạn.

Đây là một sửa chữa hoàn toàn hợp pháp! Khắc phục sự cố này làm cho notifyDataSetChanged hoạt động giống như một Bộ chuyển đổi thông thường mà không cần xem tái chế. Nếu bạn thực hiện sửa lỗi này và hiệu suất đạt yêu cầu, bạn sẽ rời khỏi cuộc đua. Công việc hoàn thành.

Nếu bạn cần hiệu suất tốt hơn, bạn có thể sử dụng getItemPosition()triển khai fancier . Đây là một ví dụ cho một máy nhắn tin tạo ra các đoạn trong danh sách các chuỗi:

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

Với cách triển khai này, chỉ các đoạn hiển thị tiêu đề mới sẽ được hiển thị. Thay vào đó, bất kỳ phân đoạn nào hiển thị các tiêu đề vẫn còn trong danh sách sẽ được chuyển đến vị trí mới trong danh sách và các phân đoạn có tiêu đề không còn trong danh sách sẽ bị hủy.

Điều gì xảy ra nếu đoạn không được tạo lại, nhưng dù sao cũng cần phải cập nhật? Cập nhật cho một mảnh sống được xử lý tốt nhất bởi chính mảnh đó. Rốt cuộc, đó là lợi thế của việc có một mảnh - đó là bộ điều khiển riêng của nó. Một đoạn có thể thêm một người nghe hoặc một người quan sát vào một đối tượng khác onCreate(), và sau đó loại bỏ nó trong onDestroy(), do đó quản lý các bản cập nhật. Bạn không cần phải đặt tất cả mã cập nhật bên trong getItem()giống như bạn làm trong một bộ chuyển đổi cho các loại ListView hoặc các loại Adaptor khác.

Một điều cuối cùng - chỉ vì FragmentPagerAdOG không phá hủy một đoạn không có nghĩa là getItemPocation hoàn toàn vô dụng trong FragmentPagerAd CHƯƠNG. Bạn vẫn có thể sử dụng cuộc gọi lại này để sắp xếp lại các đoạn của mình trong ViewPager. Tuy nhiên, nó sẽ không bao giờ xóa chúng hoàn toàn khỏi FragmentManager.


4
Không hoạt động, nó vẫn không cập nhật bất cứ điều gì ... đã đăng mã của tôi.
Ixx

64
Được rồi, đã tìm ra vấn đề - bạn cần sử dụng FragmentStatePagerAd CHƯƠNG chứ không phải FragmentPagerAd CHƯƠNG. FragmentPagerAdOG không bao giờ loại bỏ các đoạn khỏi FragmentManager, nó chỉ tách ra và đính kèm chúng. Kiểm tra tài liệu để biết thêm thông tin - nói chung, bạn chỉ muốn sử dụng FragmentPagerAd CHƯƠNG cho các đoạn là vĩnh viễn. Tôi đã chỉnh sửa ví dụ của mình với sự điều chỉnh.
Bill Phillips

1
Tôi sẽ xem xét điều này tại một số điểm sau ... cảm ơn câu trả lời của bạn. Và sau đó tôi chấp nhận câu trả lời của bạn nếu nó hoạt động. Trước bình luận cuối cùng của bạn, tôi đã triển khai để xóa và thêm ViewPager mới mỗi lần và nó hoạt động. Giải pháp không tốt lắm, nhưng tôi không có thời gian để thay đổi nó.
Ixx

12
Bạn nói đúng, việc thay đổi lớp của bộ chuyển đổi thành FragmentStatePagerAdOG đã khắc phục tất cả sự cố của tôi. Cảm ơn!
Ixx

2
Ngay cả khi tôi trả về POSITION_NONE, trong khi sử dụng FragmentStatePagerAdapter, tôi có thể thấy rằng nó sẽ loại bỏ đoạn của tôi và tạo phiên bản mới. Nhưng cá thể mới nhận được một BundInstanceState Bundle với trạng thái của một đoạn cũ. Làm thế nào tôi có thể phá hủy hoàn toàn đoạn đó để Bundle không có giá trị khi được tạo lại?
Hát

142

Thay vì trả lại POSITION_NONEtừ getItemPosition()và gây đầy đủ quan điểm vui chơi giải trí, làm như sau:

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

Các mảnh của bạn nên thực hiện UpdateableFragmentgiao diện:

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

và giao diện:

public interface UpdateableFragment {
   public void update(UpdateData xyzData);
}

Lớp dữ liệu của bạn:

public class UpdateData {
    //whatever you want here
}

1
Điều này có nghĩa là MainActivity của bạn cũng cần phải thực hiện giao diện ??? Xin hãy giúp tôi ra khỏi đây. Trong triển khai hiện tại của tôi, tôi đang sử dụng lớp MainActivity của mình như một người giao tiếp giữa các mảnh, vì vậy tôi đã nhầm lẫn về giải pháp này.
Rakeeb Rajbhandari

1
Ok tôi đã trả lời ở một nơi khác với việc thực hiện đầy đủ nơi tôi đang cập nhật một Fragmentcách linh hoạt, hãy xem: stackoverflow.com/questions/19891828/
Kẻ

@ M-WaJeEh có thể một số ví dụ xin vui lòng !!! Tôi có một listview với danh sách các thành phố và sau khi chọn thành phố mở viewpager (3 trang) với thông tin về thành phố này. nó hoạt động tốt nhưng sau khi chọn chế độ xem thành phố khác, chỉ hiển thị trang 3 d page on refreshes the 1-st page only after swiping pages? thw 2d luôn trống. cảm ơn
SERG

4
trong số tất cả những thứ tôi đã thấy trong 2,5 ngày qua của cuộc đời làm việc của tôi .. đây là thứ duy nhất làm việc cho tôi .. tất cả các loại arigato, cảm ơn, spaciba, sukran .. n.
Orkun Ozen

2
Mẹ của rồng!, Điều này hoạt động như một cơ duyên, giải pháp duy nhất có hiệu quả với tôi ... rất nhiều !!
Sebastián Guerrero

24

cho những người vẫn phải đối mặt với cùng một vấn đề mà tôi gặp phải trước đây khi tôi có ViewPager7 mảnh vỡ. Mặc định cho các đoạn này để tải nội dung tiếng Anh từ APIdịch vụ, nhưng vấn đề ở đây là tôi muốn thay đổi ngôn ngữ từ hoạt động cài đặt và sau khi kết thúc cài đặt hoạt động tôi muốn ViewPagertrong hoạt động chính để làm mới các đoạn phù hợp với lựa chọn ngôn ngữ từ người dùng và tải nội dung tiếng Ả Rập nếu người dùng chọn tiếng Ả Rập ở đây những gì tôi đã làm để làm việc từ lần đầu tiên

1- Bạn phải sử dụng FragmentStatePagerAdOG như đã đề cập ở trên.

2- trên mainActivity i ghi đè onResume và đã làm như sau

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

3-i đã ghi đè lên getItemPosition()mPagerAd CHƯƠNG và làm cho nó trở lại POSITION_NONE.

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

làm việc như quyến rũ


1
Hoạt động ngoại trừ trong một situtaion. Khi bạn xóa mục cuối cùng trong viewPager. Sau đó, nó không xóa khỏi danh sách.
Vlado Pandžić

Tôi đã thêm các đoạn vào cả bên trái và bên phải của đoạn hiện tại trong chế độ xem một cách linh hoạt. Cái này làm việc! Cảm ơn.
h8pathak

15

Tôi đã gặp phải vấn đề này và cuối cùng đã giải quyết nó ngày hôm nay, vì vậy tôi viết ra những gì tôi đã học được và tôi hy vọng nó hữu ích cho những người mới sử dụng Android ViewPagervà cập nhật như tôi. Tôi đang sử dụng FragmentStatePagerAdapterAPI cấp 17 và hiện chỉ có 2 phân đoạn. Tôi nghĩ rằng phải có một cái gì đó không đúng, xin vui lòng sửa cho tôi, cảm ơn. nhập mô tả hình ảnh ở đây

  1. Dữ liệu nối tiếp phải được tải vào bộ nhớ. Điều này có thể được thực hiện bằng cách sử dụng CursorLoader/ AsyncTask/ Thread. Việc nó tự động được tải hay không phụ thuộc vào mã của bạn. Nếu bạn đang sử dụng CursorLoader, nó sẽ tự động được tải vì có người quan sát dữ liệu đã đăng ký.

  2. Sau khi bạn gọi viewpager.setAdapter(pageradapter), bộ chuyển đổi getCount()liên tục được gọi để tạo các đoạn. Vì vậy, nếu dữ liệu đang được tải, getCount()có thể trả về 0, do đó bạn không cần tạo các mảnh giả để không có dữ liệu được hiển thị.

  3. Sau khi dữ liệu được tải, bộ điều hợp sẽ không tự động xây dựng các đoạn vì getCount()vẫn là 0, vì vậy chúng ta có thể đặt số dữ liệu thực sự được tải trở lại getCount(), sau đó gọi bộ điều hợp notifyDataSetChanged(). ViewPagerbắt đầu tạo các đoạn (chỉ 2 đoạn đầu tiên) bằng dữ liệu trong bộ nhớ. Nó được thực hiện trước khi notifyDataSetChanged()được trả lại. Sau đó, ViewPagercó những mảnh đúng bạn cần.

  4. Nếu dữ liệu trong cơ sở dữ liệu và bộ nhớ đều được cập nhật (ghi qua) hoặc chỉ dữ liệu trong bộ nhớ được cập nhật (ghi lại) hoặc chỉ dữ liệu trong cơ sở dữ liệu được cập nhật. Trong hai trường hợp cuối cùng nếu dữ liệu không được tự động tải từ cơ sở dữ liệu vào bộ nhớ (như đã đề cập ở trên). Bộ ViewPagerđiều hợp và máy nhắn tin chỉ xử lý dữ liệu trong bộ nhớ.

  5. Vì vậy, khi dữ liệu trong bộ nhớ được cập nhật, chúng ta chỉ cần gọi bộ điều hợp notifyDataSetChanged(). Vì đoạn đã được tạo, bộ điều hợp onItemPosition()sẽ được gọi trước khi notifyDataSetChanged()trả về. Không có gì cần phải được thực hiện trong getItemPosition(). Sau đó, dữ liệu được cập nhật.


Tôi đã tìm thấy những gì không cần làm sau khi bạn cập nhật dữ liệu (trong memeory), chỉ cần gọi notifyDataSetChanged()rồi tự động cập nhật, vì đoạn (với chartview) tôi sử dụng sẽ tự làm mới. nếu không, giống như một đoạn tĩnh, tôi sẽ phải gọi onItemPositon()và trả lời POSITION_NONE xin lỗi về điều đó
oscarthecat

Có ai có ý tưởng về công cụ nào đã được sử dụng để tạo sơ đồ đó không?
JuiCe

12

Hãy thử destroyDrawingCache()trên ViewPager sau notifyDataSetChanged()trong mã của bạn.


3
Tương tự ở đây. Công trình tuyệt vời cảm ơn bạn. Tôi đã có một thời gian đặc biệt khó khăn vì tôi không sử dụng Fragmentstrong máy nhắn tin xem của tôi. Cảm ơn!
Seth

11

Sau giờ thất vọng khi cố gắng tất cả các giải pháp trên để khắc phục vấn đề này và cũng cố gắng rất nhiều giải pháp về các vấn đề khác tương tự như này , nàynày mà tất cả FAILED với tôi để giải quyết vấn đề này và để thực hiện ViewPagerđể tiêu diệt cái cũ Fragmentvà lấp đầy pagervới Fragments mới . Tôi đã giải quyết vấn đề như sau:

1) Làm cho ViewPagerlớp mở rộng FragmentPagerAdapternhư sau:

 public class myPagerAdapter extends FragmentPagerAdapter {

2) Tạo một mục cho ViewPagercửa hàng đó titlefragmentnhư sau:

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) Tạo hàm tạo của cá thể ViewPagercủa tôi FragmentManagerđể lưu trữ nó trong của tôi classnhư sau:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

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

4) Tạo ra một phương pháp để tái thiết lập các adapterdữ liệu với các dữ liệu mới bằng cách xóa tất cả các trước fragmenttừ fragmentManagerbản thân trực tiếp để thực hiện adapterđể thiết lập mới fragmenttừ danh sách mới một lần nữa như sau:

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) Từ thùng chứa Activityhoặc Fragmentkhông khởi tạo lại bộ chuyển đổi với dữ liệu mới. Đặt dữ liệu mới thông qua phương thức setPagerItemsvới dữ liệu mới như sau:

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

Tôi hy vọng nó sẽ giúp.


bạn có thể giúp tôi trong vấn đề stackoverflow.com/questions/40149039/
albert

bạn có thể vui lòng giúp tôi với vấn đề này stackoverflow.com/questions/41547995/ Khăn
viper

10

Vì một số lý do, không có câu trả lời nào phù hợp với tôi vì vậy tôi đã phải ghi đè phương thức restoreState mà không gọi siêu trong FragmentStatePagerAd CHƯƠNG của tôi. Mã số:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {}

}

1
Sau khi thử mọi thứ khác trong câu trả lời SO này, đây là câu trả lời cho tôi. Tôi kết thúc () trong một hoạt động quay trở lại Hoạt động lưu trữ PagerAd CHƯƠNG được đề cập. Tôi muốn tất cả các mảnh vỡ của mình được tạo lại trong trường hợp này bởi vì Hoạt động mà tôi vừa hoàn thành có thể đã thay đổi trạng thái được sử dụng để vẽ các mảnh vỡ.
JohnnyLambada

OMG .. nó hoạt động .. nó hoạt động .. kudos: D Trong trường hợp của tôi, tôi cần phải loại bỏ đối tượng mục hiện tại của viewpager. nhưng đoạn hiện tại không cập nhật sau khi thử tất cả các phương pháp / bước trên.
Rahul Khurana

3

Tôi đã sửa đổi một chút giải pháp do Bill Phillips cung cấp cho phù hợp với nhu cầu của tôi

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

do đó getItemPosition()lợi nhuận POSITION_NONEchỉ dành cho những mảnh vỡ mà hiện nay đang ở trong FragmentManagerkhi getItemPositionđược gọi. (Lưu ý rằng cái này FragmentStatePagervà cái được ViewPagerliên kết với nó được chứa trong một mảnh vỡ không có trong Hoạt động)


2

Tôi đã có một vấn đề tương tự nhưng không muốn tin tưởng vào các giải pháp hiện có (tên thẻ được mã hóa cứng, v.v.) và tôi không thể làm cho giải pháp của M-WaJeEh hoạt động với tôi. Đây là giải pháp của tôi:

Tôi giữ các tham chiếu đến các đoạn được tạo trong getItem trong một mảng. Điều này hoạt động tốt miễn là hoạt động không bị hủy do cấu hình Thay đổi hoặc thiếu bộ nhớ hoặc bất cứ điều gì (-> khi quay lại hoạt động, các đoạn trở lại trạng thái cuối cùng mà không được gọi lại 'getItem' và do đó không cập nhật mảng ).

Để tránh vấn đề này, tôi đã triển khai InstantiateItem (Viewgroup, int) và cập nhật mảng của tôi ở đó, như thế này:

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

Vì vậy, một mặt tôi rất vui vì tôi đã tìm thấy một giải pháp phù hợp với mình và muốn chia sẻ nó với bạn, nhưng tôi cũng muốn hỏi liệu có ai đó đã thử một thứ tương tự không và liệu có lý do nào khiến tôi không nên làm như vậy? Cho đến nay nó hoạt động rất tốt cho tôi ...


Tôi đã làm một cái gì đó liên quan trong stackoverflow.com/a/23427215/954643 , mặc dù có lẽ bạn nên loại bỏ các mục từ myFragmentstrong public void destroyItem(ViewGroup container, int position, Object object)cũng vì vậy bạn không lấy một tài liệu tham khảo fragement cũ.
qix

1

Tôi sử dụng thư viện EventBus để cập nhật Fragmentnội dung ViewPager. Logic rất đơn giản, giống như tài liệu của EventBus phải làm như thế nào . Nó không cần phải kiểm soát FragmentPagerAdapterthể hiện. Mã ở đây:

1: Xác định sự kiện

Xác định thông điệp nào cần thiết để cập nhật.

public class UpdateCountEvent {
    public final int count;

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

2. Chuẩn bị thuê bao

Viết mã dưới đây trong Fragment cần cập nhật.

@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.Post sự kiện

Viết mã dưới đây Activityhoặc khác Fragmentmà cần cập nhật tham số

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

1

Nếu bạn muốn sử dụng FragmentStatePagerAdOG, vui lòng xem https://code.google.com.vn/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary 20Stars & groupby = & sort = & id = 37990 . Có những vấn đề với FragmentStatePagerAdOG có thể hoặc không thể gây rắc rối cho trường hợp sử dụng của bạn.

Ngoài ra, liên kết có một số giải pháp quá..few có thể phù hợp với yêu cầu của bạn.


Từ URL đó tôi tìm thấy giải pháp. Tôi đã sử dụng FragmentStatePagerAdOG đã sửa đổi từ ý chính này gist.github.com/ypresto/8c13cb88a0973d071a64 trong mã của tôi và nó bắt đầu hoạt động như mong muốn.
Rafael

Mát mẻ. Đúng. Liên kết có ít giải pháp quá.
cgr

1

Tôi đã sống cùng một vấn đề và tôi đã tìm kiếm quá nhiều lần. Bất kỳ câu trả lời nào được đưa ra trong stackoverflow hoặc qua google không phải là giải pháp cho vấn đề của tôi. Vấn đề của tôi rất dễ dàng. Tôi có một danh sách, tôi hiển thị danh sách này với viewpager. Khi tôi thêm một yếu tố mới vào đầu danh sách và tôi làm mới các thông báo của chế độ xem đã thay đổi. Giải pháp cuối cùng của tôi là rất dễ dàng bất cứ ai có thể sử dụng. Khi một yếu tố mới được thêm vào danh sách và muốn làm mới danh sách. Trước tiên, đặt bộ điều hợp viewpager thành null, sau đó tạo lại bộ điều hợp và đặt i thành nó cho viewpager.

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

Hãy chắc chắn bộ điều hợp của bạn phải mở rộng FragmentStatePagerAd CHƯƠNG


1

Đây là cách triển khai của tôi kết hợp thông tin từ @Bill Phillips One được lưu vào bộ nhớ cache phân đoạn, trừ khi dữ liệu đã thay đổi. Đơn giản, và dường như hoạt động tốt.

MyFragmentStatePagerAd Module.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);
    }
}

MyActivity.java

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

0

Tôi đã thử rất nhiều cách tiếp cận khác nhau, không có cách nào thực sự giải quyết được vấn đề của tôi. Dưới đây là cách tôi giải quyết nó với một loạt các giải pháp được cung cấp bởi tất cả các bạn. Cảm ơn mọi người.

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

Tôi chỉ muốn làm mới trang 0 sau onResume ().

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

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

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

Trong FragmentsMain của tôi, có "trang" số nguyên công khai, có thể cho tôi biết đó có phải là trang tôi muốn làm mới hay không.

public class FragmentsMain extends Fragment {

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

0

Tôi biết là muộn cho Đảng. Tôi đã khắc phục sự cố bằng cách gọi TabLayout#setupWithViewPager(myViewPager);ngay sau đóFragmentPagerAdapter#notifyDataSetChanged();


0

Giải pháp này sẽ không hiệu quả với tất cả mọi người, nhưng trong trường hợp của tôi, mỗi Fragment trong ViewPager của tôi là một lớp khác nhau và chỉ có một trong số chúng tồn tại tại một thời điểm.

Với hạn chế này, giải pháp này là an toàn và nên an toàn để sử dụng trong sản xuất.

private void updateFragment(Item item) {

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

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

    }
}

Nếu bạn có nhiều phiên bản của cùng một đoạn, bạn có thể sử dụng cùng một chiến lược này để gọi các phương thức trên các đoạn đó để xác định xem đó có phải là đoạn bạn muốn cập nhật hay không.


0

Điều này có thể giúp ích cho ai đó - trong trường hợp của tôi khi chèn một trang mới, máy nhắn tin xem đã yêu cầu vị trí của một đoạn hiện tại hai lần, nhưng không yêu cầu vị trí của mục mới, khiến hành vi và dữ liệu không chính xác không hiển thị.

  1. Sao chép nguồn cho FragmentStatePagerAdOG (dường như chưa được cập nhật theo thời gian).

  2. Ghi đè thông báoDataSetChanged ()

    @Override
    public void notifyDataSetChanged() {
        mFragments.clear();
        super.notifyDataSetChanged();
    }
  3. Thêm kiểm tra độ tỉnh để phá hủyItem () để ngăn sự cố:

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

0

Tôi đã xem qua tất cả các câu trả lời ở trên và một số bài đăng khác nhưng vẫn không thể tìm thấy nội dung nào phù hợp với tôi (với các loại phân đoạn khác nhau cùng với việc thêm và xóa động các tab). Cách tiếp cận theo FWIW là những gì làm việc cho tôi (trong trường hợp bất kỳ ai khác có cùng vấn đề).

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

0

Sử dụng FragmentStatePagerAd CHƯƠNG thay vì FragmentPagerAdRAM nếu bạn muốn tạo lại hoặc tải lại đoạn trên cơ sở chỉ mục Ví dụ: nếu bạn muốn tải lại đoạn khác ngoài FirstFragment, bạn có thể kiểm tra ví dụ và trả về vị trí như thế này

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

0

Bạn cần thay đổi phần tử mFragments của ngay lập tức getItemPocation.

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

Dựa trên AndroidX FragmentStatePagerAd Module.java, vì mFragmentsvị trí của các thành phần không thay đổi khi gọi notifyDataSetChanged ().

Nguồn: https://github.com/cuichanghao/infivt/blob/master/l Library / src / main / java / cc / cuichanghao / thư viện / FragmentStatePagerChangizableAd Module.java

Ví dụ: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangizablePager.kt

Bạn có thể chạy dự án này để xác nhận cách làm việc. https://github.com/cuichanghao/infivt

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.