2012-01-29 49 views
6

(Nếu ai đó cần thêm thông tin, hoặc một mô tả tốt hơn cho tôi biết)ViewPager: Nếu trang bị loại bỏ các nội dung trang tiếp theo được trang bị loại bỏ nội dung

Xin chào tôi bao gồm các viewPagerLibrary từ đây: http://viewpagerindicator.com/#introduction hôm nay dự án của tôi.

Không, tôi gặp vấn đề thực sự lạ: Nếu tôi thêm trang hoặc trang (hãy gọi trang web đó trong vài dòng tiếp theo) và xóa lại mọi thứ đều ổn. Nhưng nếu tôi cố gắng để thêm một trang khác nhau (Những trang đó là các Fragements khác nhau mà thực hiện một lớp BaseFragment) nội dung của trang đầu tiên được hiển thị. Điều tương tự cũng xảy ra nếu tôi thêm một vài trang và xóa một trang giữa các trang đó. Trang sau trang bị xóa hiển thị nội dung trang đã xóa.

Ví dụ về lỗi này: Vấn đề hiện tại là. Nếu tôi thêm FragmentA sau đó FragmentB, sau đó tôi xóa FragmentA, FragmentB nhận được khung nhìn/nội dung của FragmentA. Điều kỳ lạ là, đối tượng là đúng (Vì vậy, bộ điều hợp trả lại đối tượng chính xác) và Tiêu đề cũng đúng.

Trong chính của tôi tạo Pager, Chỉ thị và Adaptor của tôi theo cách này:

Cfg.mAdapter = new FragmentAdapter(getSupportFragmentManager()); 

    Cfg.mPager = (ViewPager)findViewById(R.id.pager); 
    Cfg.mPager.setAdapter(Cfg.mAdapter); 

    Cfg.mIndicator = (TabPageIndicator)findViewById(R.id.indicator); 
    Cfg.mIndicator.setViewPager(Cfg.mPager); 

    //We set this on the indicator, NOT the pager 
    Cfg.mIndicator.setOnPageChangeListener(TabHelper.onPageChangeListener); 

(Các CFG là một tập tin tĩnh để lưu trữ những thứ đó cho việc sử dụng)

BaseFragment của tôi trông giống như sau :

public class BaseFragment extends Fragment{ 

    public static int FILE_FRAGMENT = 0; 
    public static int FTP_FRAGMENT = 1; 
    public static int ADDFTP_FRAGMENT = 2; 
    public static int PREVIEW_FRAGMENT = 3; 
    public static int CSS_FRAGMENT = 4; 
    public static int BOOKS_FRAGMENT = 5; 
    public static int SNIPPETS_FRAGMENT = 6; 

    //private int id; 
    private int typ; 
    private String title; 

    public int getTyp() { 
     return typ; 
    } 

    public void setTyp(int typ) { 
     this.typ = typ; 
    } 

    public String getTitle() { 
     return title; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 
} 

Một trong những mảnh vỡ trông như thế này (tôi nghĩ rằng các mảnh vỡ khác làm cho không có sự khác biệt):

public class FtpFragment extends BaseFragment { 
    private static RowLayout rowLayout_view; 

    public FtpFragment() { 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     init_data(); 
    } 

    public static void init_data() 
    { 
     //Remove child for update 
     rowLayout_view.removeAllViews(); 

     List<FtpData> ftps = FtpStorage.getInstance().getFtps(); 

     if (ftps != null) { 
      for (FtpData f : ftps) { 
       View inflatedView; 
       inflatedView = View.inflate(Cfg.ctx, R.layout.ftp, null); 
       inflatedView.setOnClickListener(button_ftp_listener); 
       inflatedView.setOnLongClickListener(button_ftp_longClickListener); 
       inflatedView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, Converter.convertFromDPtoPixel(160.0f))); 
       inflatedView.setTag(f); 
       inflatedView.findViewById(R.id.book_imageview).setBackgroundDrawable(
           Cfg.ctx.getResources().getDrawable(R.drawable.nopreview)); 


       ((TextView) inflatedView.findViewById(R.id.book_textview)).setText(f.nickname); 

       rowLayout_view.addView(inflatedView); 
      } 
     } 
    } 

    @Override 

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    View v = inflater.inflate(R.layout.fragment_ftp, container, false); 
    rowLayout_view = (RowLayout) v.findViewById(R.id.rowLayout_ftps); 
    return v; 
} 

@Override 
public String getTitle() { 
    return "FTPs"; 
} 

@Override 
public int getTyp() { 
    return BaseFragment.FTP_FRAGMENT; 
} 

@Override 
public void setTyp(int typ) { 
    super.setTyp(typ); 
} 

}

Để xóa hoặc thêm một trang tôi gọi đây là:

public static void addNewTab(BaseFragment fragment) 
{ 
    Cfg.mAdapter.addItem(fragment); 
    Cfg.mPager.setCurrentItem(Cfg.mAdapter.getCount()); 
    Cfg.mIndicator.notifyDataSetChanged(); 
} 

public static void deleteActTab() 
{ 
    Cfg.mAdapter.removeItem(Cfg.mAdapter.getActPage()); 
    Cfg.mIndicator.notifyDataSetChanged(); 
} 

Và đó là adapter:

public class FragmentAdapter extends FragmentPagerAdapter implements TitleProvider{ 
    public List<BaseFragment> fragments = new LinkedList<BaseFragment>(); 

    private int actPage; 

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


    public void setActPage(int actPage) { 
     Lg.d("setActPage: " + actPage + " : " + fragments.get(actPage).toString()); 
     this.actPage = actPage; 
    } 

    public void addItem(BaseFragment fragment) 
    { 
     Lg.d("addItem: " + fragment.toString()); 
     fragments.add(fragment); 
    } 

    public void removeItem(int index) 
    { 
     if(index < getCount()){ 
      Lg.d("RemoveItem: " + index + " : " + fragments.get(index).toString()); 
      fragments.remove(index); 
     } 
    } 

    public BaseFragment getActFragment() 
    { 
     return getItem(getActPage()); 
    } 

    public int getActPage() { 
     return actPage; 
    } 

    @Override 
    public BaseFragment getItem(int position) { 
     if(position < getCount()) 
     { 
      Lg.v("getItem: " + fragments.get(position)); 
      return fragments.get(position); 
     } 
     else 
      return null; 
    } 

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

    @Override 
    public String getTitle(int position) { 
     Lg.v("Get Title: " + fragments.get(position).getTitle()); 
     return fragments.get(position).getTitle(); 
    } 

} 

Vâng tôi hy vọng ai đó có thể giúp tôi.

Nếu tôi quên điều gì đó, hãy để tôi konw.

Cảm ơn trước, Mike

+0

bất kỳ đề xuất nào về vấn đề được đề cập ở đây http://stackoverflow.com/q/25159181/2624806 – CoDe

Trả lời

2

Ok bây giờ tôi đã giải quyết được vấn đề của mình theo cách hackish, nhưng vâng nó hoạt động;). Nếu ai đó có thể cải thiện giải pháp của tôi, vui lòng cho tôi biết. Đối với giải pháp mới của tôi bây giờ tôi sử dụng một CustomFragmentStatePagerAdapter nhưng nó không lưu trạng thái như nó nên và lưu trữ tất cả các Fragments trong một danh sách.Điều này có thể gây ra vấn đề về bộ nhớ nếu người dùng có nhiều hơn 50 đoạn, giống như FragmentPagerAdapter bình thường. Sẽ thật tuyệt vời nếu ai đó có thể thêm lại trạng thái vào giải pháp của tôi mà không xóa các bản sửa lỗi của tôi. Cảm ơn.

Vì vậy, đây là tôi CustomFragmentStatePagerAdapter.java

package com.tundem.webLab.Adapter; 

import java.util.ArrayList; 

import android.os.Bundle; 
import android.os.Parcelable; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentTransaction; 
import android.support.v4.view.PagerAdapter; 
import android.util.Log; 
import android.view.View; 
import android.view.ViewGroup; 

public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter { 
    private static final String TAG = "FragmentStatePagerAdapter"; 
    private static final boolean DEBUG = false; 

    private final FragmentManager mFragmentManager; 
    private FragmentTransaction mCurTransaction = null; 

    public ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>(); 
    public ArrayList<Fragment> mFragments = new ArrayList<Fragment>(); 
    private Fragment mCurrentPrimaryItem = null; 

    public CustomFragmentStatePagerAdapter(FragmentManager fm) { 
     mFragmentManager = fm; 
    } 

    /** 
    * Return the Fragment associated with a specified position. 
    */ 
    public abstract Fragment getItem(int position); 

    @Override 
    public void startUpdate(ViewGroup container) {} 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     // If we already have this item instantiated, there is nothing 
     // to do. This can happen when we are restoring the entire pager 
     // from its saved state, where the fragment manager has already 
     // taken care of restoring the fragments we previously had instantiated. 

     // DONE Remove of the add process of the old stuff 
     /* if (mFragments.size() > position) { Fragment f = mFragments.get(position); if (f != null) { return f; } } */ 

     if (mCurTransaction == null) { 
      mCurTransaction = mFragmentManager.beginTransaction(); 
     } 

     Fragment fragment = getItem(position); 
     if (DEBUG) 
      Log.v(TAG, "Adding item #" + position + ": f=" + fragment); 
     if (mSavedState.size() > position) { 
      Fragment.SavedState fss = mSavedState.get(position); 
      if (fss != null) { 
       try // DONE: Try Catch 
       { 
        fragment.setInitialSavedState(fss); 
       } catch (Exception ex) { 
        // Schon aktiv (kA was das heißt xD) 
       } 
      } 
     } 
     while (mFragments.size() <= position) { 
      mFragments.add(null); 
     } 
     fragment.setMenuVisibility(false); 
     mFragments.set(position, fragment); 
     mCurTransaction.add(container.getId(), fragment); 

     return fragment; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     Fragment fragment = (Fragment) object; 

     if (mCurTransaction == null) { 
      mCurTransaction = mFragmentManager.beginTransaction(); 
     } 
     mCurTransaction.remove(fragment); 

     /*if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment) 
     * object).getView()); while (mSavedState.size() <= position) { mSavedState.add(null); } mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); 
     * mFragments.set(position, null); mCurTransaction.remove(fragment); */ 
    } 

    @Override 
    public void setPrimaryItem(ViewGroup container, int position, Object object) { 
     Fragment fragment = (Fragment) object; 
     if (fragment != mCurrentPrimaryItem) { 
      if (mCurrentPrimaryItem != null) { 
       mCurrentPrimaryItem.setMenuVisibility(false); 
      } 
      if (fragment != null) { 
       fragment.setMenuVisibility(true); 
      } 
      mCurrentPrimaryItem = fragment; 
     } 
    } 

    @Override 
    public void finishUpdate(ViewGroup container) { 
     if (mCurTransaction != null) { 
      mCurTransaction.commitAllowingStateLoss(); 
      mCurTransaction = null; 
      mFragmentManager.executePendingTransactions(); 
     } 
    } 

    @Override 
    public boolean isViewFromObject(View view, Object object) { 
     return ((Fragment) object).getView() == view; 
    } 

    @Override 
    public Parcelable saveState() { 
     Bundle state = null; 
     if (mSavedState.size() > 0) { 
      state = new Bundle(); 
      Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; 
      mSavedState.toArray(fss); 
      state.putParcelableArray("states", fss); 
     } 
     for (int i = 0; i < mFragments.size(); i++) { 
      Fragment f = mFragments.get(i); 
      if (f != null) { 
       if (state == null) { 
        state = new Bundle(); 
       } 
       String key = "f" + i; 
       mFragmentManager.putFragment(state, key, f); 
      } 
     } 
     return state; 
    } 

    @Override 
    public void restoreState(Parcelable state, ClassLoader loader) { 
     if (state != null) { 
      Bundle bundle = (Bundle) state; 
      bundle.setClassLoader(loader); 
      Parcelable[] fss = bundle.getParcelableArray("states"); 
      mSavedState.clear(); 
      mFragments.clear(); 
      if (fss != null) { 
       for (int i = 0; i < fss.length; i++) { 
        mSavedState.add((Fragment.SavedState) fss[i]); 
       } 
      } 
      Iterable<String> keys = bundle.keySet(); 
      for (String key : keys) { 
       if (key.startsWith("f")) { 
        int index = Integer.parseInt(key.substring(1)); 
        Fragment f = mFragmentManager.getFragment(bundle, key); 
        if (f != null) { 
         while (mFragments.size() <= index) { 
          mFragments.add(null); 
         } 
         f.setMenuVisibility(false); 
         mFragments.set(index, f); 
        } else { 
         Log.w(TAG, "Bad fragment at key " + key); 
        } 
       } 
      } 
     } 
    } 
} 

Dưới đây là bình thường của tôi FragmentAdapter.java

package com.tundem.webLab.Adapter; 

import java.util.LinkedList; 
import java.util.List; 

import android.support.v4.app.FragmentManager; 

import com.tundem.webLab.fragments.BaseFragment; 
import com.viewpagerindicator.TitleProvider; 

public class FragmentAdapter extends CustomFragmentStatePagerAdapter implements TitleProvider { 
    public List<BaseFragment> fragments = new LinkedList<BaseFragment>(); 

    private int actPage; 

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

    public void setActPage(int actPage) { 
     this.actPage = actPage; 
    } 

    public void addItem(BaseFragment fragment) { 
     // TODO if exists don't open/change to that tab 
     fragments.add(fragment); 
    } 

    public BaseFragment getActFragment() { 
     return getItem(getActPage()); 
    } 

    public int getActPage() { 
     return actPage; 
    } 

    @Override 
    public BaseFragment getItem(int position) { 
     if (position < getCount()) { 
      return fragments.get(position); 
     } else 
      return null; 
    } 

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

    @Override 
    public String getTitle(int position) { 
     return fragments.get(position).getTitle(); 
    } 

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

Và đây là cách tôi xóa một Fragment. (Tôi biết nó nhiều hơn một chút so với chỉ .remove()). Được tự do cải thiện giải pháp của tôi, bạn cũng có thể thêm mã này vào đâu đó trong bộ điều hợp để vâng. Tùy thuộc vào người dùng cố thực hiện điều này. Tôi sử dụng này trong tôi TabHelper.java (Một lớp học mà xử lý tất cả các hoạt động tab như xóa, thêm, ...)

int act = Cfg.mPager.getCurrentItem(); 
    Cfg.mPager.removeAllViews(); 
    Cfg.mAdapter.mFragments.remove(act); 
    try { 
     Cfg.mAdapter.mSavedState.remove(act); 
    } catch (Exception ex) {/* Already removed */} 
    try { 
     Cfg.mAdapter.fragments.remove(act); 
    } catch (Exception ex) {/* Already removed */} 

    Cfg.mAdapter.notifyDataSetChanged(); 
    Cfg.mIndicator.notifyDataSetChanged(); 

Mô tả của CFG. Điều. Tôi lưu tham chiếu đến các đối tượng đó trong một lớp cfg, vì vậy tôi luôn có thể sử dụng chúng mà không cần một Factory.java đặc biệt ...

Vâng. tôi hy vọng tôi đã có thể giúp đỡ. Vui lòng cải thiện điều này, nhưng hãy cho tôi biết để tôi cũng có thể cải thiện mã của mình.

Cảm ơn.

Nếu tôi bỏ lỡ bất kỳ mã nào cho tôi biết.


Câu trả lời cũ của tôi cũng hoạt động nhưng chỉ khi bạn có các phân đoạn khác nhau. FileFragment, WebFragment, ... Không nếu bạn sử dụng một trong những fragmenttypes hai lần.

Tôi đã làm cho nó hoạt động ngay bây giờ. Đó là một giải pháp thực sự bẩn và tôi vẫn đang tìm kiếm một giải pháp tốt hơn. Hãy giúp tôi.

tôi đã thay đổi mã này, nơi mà tôi xóa một tab bên dưới:

public static void deleteActTab() 
     { 
      //We set this on the indicator, NOT the pager 
      int act = Cfg.mPager.getCurrentItem(); 
      Cfg.mAdapter.removeItem(act); 
      List<BaseFragment> frags = new LinkedList<BaseFragment>(); 
      frags = Cfg.mAdapter.fragments; 

      Cfg.mPager = (ViewPager)Cfg.act.findViewById(R.id.pager); 
      Cfg.mPager.setAdapter(Cfg.mAdapter); 
      Cfg.mIndicator.setViewPager(Cfg.mPager); 

      Cfg.mAdapter.fragments = frags; 

      if(act > 0) 
      { 
       Cfg.mPager.setCurrentItem(act-1); 
       Cfg.mIndicator.setCurrentItem(act-1); 
      } 

      Cfg.mIndicator.notifyDataSetChanged(); 
     } 

Nếu ai đó có thể cải thiện mã này cho tôi biết. Nếu ai đó có thể cho chúng tôi biết câu trả lời thực sự cho vấn đề đó. xin vui lòng thêm nó ở đây. Có rất nhiều người gặp phải vấn đề này. Tôi đã thêm một danh tiếng là 50 cho người giải quyết nó. Tôi cũng có thể quyên góp cho người giải quyết nó.

Cảm ơn

0

Trong câu trả lời của bạn (bằng cách mikepenz), bạn không cần phải thiết lập các bộ chuyển đổi một lần nữa. Bạn có thể gọi cho notificationDataSetChanged.

public static void deleteActTab(){ 

     //We set this on the indicator, NOT the pager 
     int act = Cfg.mPager.getCurrentItem(); 
     Cfg.mAdapter.removeItem(act);   


     if(act > 0) 
     { 
      Cfg.mPager.setCurrentItem(act-1); 
      Cfg.mIndicator.setCurrentItem(act-1); 
     } 
     //Also add conditions to check if there are any remaining fragments 


     Cfg.mIndicator.notifyDataSetChanged(); 
} 

Bạn có xem xét sử dụng HashMap<Integer, Fragment> hoặc ArrayAdapter<Fragment> để cải thiện hiệu suất hoặc đã sử dụng nó? Ngoài ra, tại sao bạn sử dụng phương pháp tĩnh trong BaseFragment? Vui lòng xem xét sử dụng MAT hoặc logcat để kiểm tra mức sử dụng bộ nhớ nếu bộ nhớ bị rò rỉ này.

+0

Như bạn có thể thấy trong câu hỏi ban đầu của mình, tôi đã làm như bạn đề cập đến ở đây.Nhưng điều này không hoạt động vì nội dung sẽ không cập nhật chính xác. Có vẻ như mPager không quản lý các mảnh đúng. Bạn có thể đưa ra một mã ví dụ nâng cao hơn về ý nghĩa của bạn với HashMap hoặc ArrayAdapter không? Hãy ghi nhớ rằng tôi sử dụng các mảnh vỡ khác nhau để mở rộng BaseFragment của tôi. – mikepenz

0

Để tránh vấn đề này, bạn phải gỡ bỏ đoạn xác định từ backstack. Mỗi khi bạn xóa một đoạn khỏi danh sách của mình, nó vẫn còn ở backstack để nội dung sẽ vẫn còn. Trước khi xóa phân đoạn khỏi danh sách của bạn, bạn phải sử dụng FragmentTransaction để xóa trang. Sau đó, mã có thể là một cái gì đó như thế này.

public void removePage(int currentPage) { 
    for (int i = pageFragmentList.size() - 1; i >= currentPage; i--) { 
     ((MainActivity) context).getSupportFragmentManager().beginTransaction() 
       .remove(pageFragmentList.get(i)).commit(); 
    } 
    pageFragmentList.remove(currentPage); 
} 

Nếu bạn không loại bỏ tất cả các trang được lập chỉ mục sau trang hiện tại, và chỉ loại bỏ các trang hiện tại từ backstack, nó có thể ném một ngoại lệ.

Các vấn đề liên quan