9

我从 Web 服务接收数据,该数据被解析为Application类中的一个对象,这个对象在我的例子中是一个Report类,它包含一个Tabs应该填充ViewPager. 所以这个报表存储在currentReportApplication类的参数中。

每个选项卡都应该是ViewPager. 因此,当我第一次收到数据并对其进行解析时,一切正常,View Pager 填充了正确的数据并显示它。

当我想从服务器获取新数据并使用解析到参数中的新数据Report刷新时,我的问题就开始了。ViewPagercurrentReport

我是可滑动的并且有标签导航,所以当我尝试用新ViewPager的重新实例化时,我看到添加到. 由于某种原因,新报告的片段与前一份报告的片段重叠。因此,如果新报告中的选项卡数量大于上一个报告中的选项卡,那么除了部分新报告之外,我还可以看到上一个报告中的选项卡(例如,如果在第一个报告中我有一个选项卡,并且在新的我有 3 个,然后我看到前一个片段的一个片段和下一个片段的最后 2 个片段)。ViewPagerReporttabHost

我已经从本教程开始我的开发并向其中添加了 smoe 代码: http ://thepseudocoder.wordpress.com/2011/10/13/android-tabs-viewpager-swipe-able-tabs-ftw/

这是我的标签活动代码:

public class TabsViewPagerFragmentActivity extends FragmentActivity implements    ViewPager.OnPageChangeListener, TabHost.OnTabChangeListener 
{
static final String TAG = TabsViewPagerFragmentActivity.class.getSimpleName();
private TabHost mTabHost;
private ViewPager mViewPager;
private HashMap<String, TabInfo> mapTabInfo;
public ViewPagerAdapter mPagerAdapter;
private TextView tvReportName, tvTabTitle;
private Button bBackToParameters;
private Dialog progressDialog;
private SGRaportManagerAppObj application;
private int numberOfTabs = 0;
private Display display;
public static final int POPUP_MARGIN = 6;
LeftSideMenu leftSideMenu;

public void NotifyTabActivityViewPagerAdapter()
{
    mPagerAdapter.notifyDataSetChanged();
}

public ViewPagerAdapter getTabActivityViewPagerAdapter()
{
    return mPagerAdapter;
}

public ViewPager getTabActivityViewPager()
{
    return mViewPager;
}

public void setCurrentTabTitle (String title)
{
    tvTabTitle.setText(title);
    Log.d(TAG, "set tab title from activity: "+title);
}


/**
* Maintains extrinsic info of a tab's construct
*/
private class TabInfo 
{
    private String tag;
    private Class<?> clss;
    private Bundle args;
    private Fragment fragment;

    TabInfo(String tag, Class<?> clazz, Bundle args) 
    {
        this.tag = tag;
        this.clss = clazz;
        this.args = args;
    }
}

/**
 * A simple factory that returns dummy views to the Tabhost
 */
class TabFactory implements TabContentFactory {

    private final Context mContext;

    /**
     * @param context
     */
    public TabFactory(Context context) {
        mContext = context;
    }

    /** (non-Javadoc)
     * @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
     */
    public View createTabContent(String tag) {
        View v = new View(mContext);
        v.setMinimumWidth(0);
        v.setMinimumHeight(0);
        return v;
    }
}

/** (non-Javadoc)
 * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
*/
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    application = SGRaportManagerAppObj.getInstance();
    display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    // Inflate the layout
    setContentView(R.layout.tabs_screen_activity_layout);
    tvTabTitle = (TextView) findViewById(R.id.tvTabName);
    tvReportName = (TextView)findViewById(R.id.tvReportName);
    tvReportName.setText(application.currentReport.getName()+ " - ");
    bBackToParameters = (Button) findViewById(R.id.bBackToParameters);
    leftSideMenu = (LeftSideMenu) findViewById(R.id.leftSideMenu);
    applyOnClickListenerToLeftSideMenu();

    findViewById(R.id.showLeftMenuButton).setOnClickListener(new View.OnClickListener() 
    {
        @Override
        public void onClick(View v) 
        {               
            Display d = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
            int width = d.getWidth();

            View panel = findViewById(R.id.leftSideMenu);
            View appPanel = findViewById(R.id.appLayout);
            if (panel.getVisibility() == View.GONE){
                appPanel.setLayoutParams(new LinearLayout.LayoutParams(width, LayoutParams.FILL_PARENT));
                panel.setVisibility(View.VISIBLE);
                applyOnClickListenerToLeftSideMenu();
            }else{
                ToggleButton button = (ToggleButton) findViewById(R.id.showLeftMenuButton);
                button.setChecked(false);
                panel.setVisibility(View.GONE);
            }
        }
    });

    // Initialise the TabHost
    progressDialog = DialogUtils.createProgressDialog(this, this.getString(R.string.populating_view_pager));
    progressDialog.show();

    if (SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository().size() == 0)
    {
        bBackToParameters.setText(R.string.back_to_report_list);
    }
    this.initialiseTabHost(savedInstanceState);

    if (savedInstanceState != null) {
        mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); //set the tab as per the saved state
    }
    // Intialise ViewPager
    this.intialiseViewPager();
    progressDialog.dismiss();
}

 /** (non-Javadoc)
 * @see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle)
 */
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected
    super.onSaveInstanceState(outState);
}

/**
 * Initialise ViewPager
 */
public void intialiseViewPager() 
{

    List<Fragment> fragments = new Vector<Fragment>();

  // TabInfo tabInfo = null;

    if (application.getCurrentDataSource().equals(DataSource.SSRS))
    {
        numberOfTabs = application.currentReport.getTabsList().size();
    }
    else if (application.getCurrentDataSource().equals(DataSource.SGRDL))
    {
        numberOfTabs = application.currentReport.getODTabsList().size();
        Log.d(TAG, "CURRENT REPORT FROM VIEW PAGER: "+ application.currentReport.toString());
    }   

    Log.d(TAG,"Current Tabs number from TabsViewPager activity: " +numberOfTabs);

    if (application.getCurrentDataSource().equals(DataSource.SSRS))
    {
         for (int i = 0; i < numberOfTabs; i++)     
         {
            Tab tempTab = application.currentReport.getTabsList().get(i);
            if (tempTab.getTabTemplateId() == 7)
            {
                GridFragment gridFragment = new GridFragment(tempTab);
                fragments.add(gridFragment);
            }
            else  if (tempTab.getTabTemplateId() == 8)
            {
                NewChartFragment chartFragment = new NewChartFragment(tempTab, this);
                fragments.add(chartFragment);
            }
         }
    }
    else if (application.getCurrentDataSource().equals(DataSource.SGRDL))
    {
         for (int i = 0; i < numberOfTabs; i++)     
         {
            ODTab tempTab = application.currentReport.getODTabsList().get(i);
            if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT))
            {
                GridFragment gridFragment = GridFragment.newInstance(tempTab.getTabId());
                fragments.add(gridFragment);
            }
            else  if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT))
            {
                NewChartFragment chartFragment = NewChartFragment.newInstance(tempTab.getTabId());
                fragments.add(chartFragment);
            }
         }
    }   

    Log.d(TAG, "Current report fragments set to adapter: "+fragments.toString());
   /*
    if (this.mPagerAdapter == null)
    {
        this.mPagerAdapter  = new ViewPagerAdapter(super.getSupportFragmentManager(), fragments);
    }
    else
    {
        this.mPagerAdapter.removeAllFragments();
        this.mPagerAdapter.addFragmentsListToAdapter(fragments);
    }
    */
    this.mPagerAdapter  = new ViewPagerAdapter(super.getSupportFragmentManager(), fragments);
    this.mViewPager = (ViewPager)super.findViewById(R.id.pager);
//    this.mViewPager.setAdapter(null);
    this.mViewPager.setAdapter(this.mPagerAdapter);
    this.mViewPager.setOffscreenPageLimit(0);
    this.mViewPager.setOnPageChangeListener(this);
    Log.d(TAG, "Adapter initialized!");
}

/**
 * Initialise the Tab Host
 */
public void initialiseTabHost(Bundle args) {
    mTabHost = (TabHost)findViewById(android.R.id.tabhost);

    /*
    //new edit
    if (mTabHost.getChildCount() > 0)
    {
        mTabHost.removeAllViews();
    }
    */

    mTabHost.setup();
    TabInfo tabInfo = null;
    mapTabInfo = new HashMap<String, TabsViewPagerFragmentActivity.TabInfo>();
    if (args != null)
    {}
    else
    {
        if (application.getCurrentDataSource().equals(DataSource.SSRS))
        {
            int numberOfTabs = application.currentReport.getTabsList().size();
            for (int i = 0; i < numberOfTabs; i++)      
            {
                Tab tempTab = application.currentReport.getTabsList().get(i);
                if (tempTab.getTabTemplateId() == 7)
                {
                    //GridFragment gridFragment = new GridFragment(tempTab);
                    TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), GridFragment.class, args)));
                    this.mapTabInfo.put(tabInfo.tag, tabInfo);
                }
                else  if (tempTab.getTabTemplateId() == 8)
                {
                    TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), NewChartFragment.class, args)));
                    this.mapTabInfo.put(tabInfo.tag, tabInfo);
                }
            }
        }

        else if (application.getCurrentDataSource().equals(DataSource.SGRDL))
        {
            int numberOfTabs = application.currentReport.getODTabsList().size();
            for (int i = 0; i < numberOfTabs; i++)      
            {
                ODTab tempTab = application.currentReport.getODTabsList().get(i);
            //  Log.d(TAG,"Crashed Tab type: "+ tempTab.getTabType());
                if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT))
                {
                    //GridFragment gridFragment = new GridFragment(tempTab);
                    TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), GridFragment.class, args)));
                    this.mapTabInfo.put(tabInfo.tag, tabInfo);
                }
                else  if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT))
                {
                    TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), NewChartFragment.class, args)));
                    this.mapTabInfo.put(tabInfo.tag, tabInfo);
                }
            }
        }
    }
    // Default to first tab
    //this.onTabChanged("Tab1");
    //
    mTabHost.setOnTabChangedListener(this);
}

/**
 * Add Tab content to the Tabhost
 * @param activity
 * @param tabHost
 * @param tabSpec
 * @param clss
 * @param args
 */
private static void AddTab(TabsViewPagerFragmentActivity activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) 
{
    // Attach a Tab view factory to the spec       
    ImageView indicator = new ImageView(activity.getBaseContext());
    indicator.setPadding(10, 10, 10, 10);
    indicator.setImageResource(R.drawable.tab_select_icon_selector);
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    lp.setMargins(10, 10, 10, 10);
    indicator.setLayoutParams(lp);
    tabSpec.setIndicator(indicator); 
    tabSpec.setContent(activity.new TabFactory(activity));
    tabHost.addTab(tabSpec);
}

/** (non-Javadoc)
 * @see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String)
 */
public void onTabChanged(String tag) {
    //TabInfo newTab = this.mapTabInfo.get(tag);
    int pos = this.mTabHost.getCurrentTab();
    this.mViewPager.setCurrentItem(pos);
}

/* (non-Javadoc)
 * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrolled(int, float, int)
 */
@Override
public void onPageScrolled(int position, float positionOffset,
        int positionOffsetPixels) {
    // TODO Auto-generated method stub

}

/* (non-Javadoc)
 * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageSelected(int)
 */
@Override
public void onPageSelected(int position) {
    // TODO Auto-generated method stub
    this.mTabHost.setCurrentTab(position);
}


/* (non-Javadoc)
 * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrollStateChanged(int)
 */
@Override
public void onPageScrollStateChanged(int state) {
    // TODO Auto-generated method stub

}

这是我的适配器代码:

public class ViewPagerAdapter extends FragmentPagerAdapter 
{
private List<Fragment> fragments;

/**
 * @param fm
 * @param fragments
 */
public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
    super(fm);
    this.fragments = fragments;
}

/* (non-Javadoc)
 * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
 */

@Override
public Fragment getItem(int position) {
    return this.fragments.get(position);
}

/* (non-Javadoc)
 * @see android.support.v4.view.PagerAdapter#getCount()
 */

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

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

我的 AsyncTask 解析数据并更新了 ViewPager:

public class ParseSGRDLReportDataAsyncTask extends AsyncTask<String, Object, Report>{

static final String TAG = ParseSGRDLReportDataAsyncTask.class.getSimpleName();
private Activity activity;  
private Exception exception;
private ResponseHandler responseHandler = new ResponseHandler();
private SGRaportManagerAppObj application;
private Dialog progressDialog;

public ParseSGRDLReportDataAsyncTask(LoginScrActivity activity) {
    super();
    this.activity = activity;
}

public ParseSGRDLReportDataAsyncTask(Activity currentActivity) {
    super();
    this.activity = currentActivity;
}

public void onPreExecute() {
    application = SGRaportManagerAppObj.getInstance();
    progressDialog = DialogUtils.createProgressDialog(activity, activity.getString(R.string.parse_data_dialog_message));
    progressDialog.show();
}

@Override
protected Report doInBackground(String... params) {

    String ReportDataString = params[0];
    try{
        return DataAccessManager.parseSGRDLReportData(ReportDataString);            
    }
    catch (Exception e) {
        exception = e;
        return null;
    }
}

@Override
public void onPostExecute(Report result) {
    progressDialog.dismiss();

    if (exception == null) 
    {
        if (activity.getClass() == TabsViewPagerFragmentActivity.class)
        {
            application.currentReport = result;
            Log.d(TAG, "Current report parsed is: "+result);

            ((TabsViewPagerFragmentActivity)activity).intialiseViewPager();

            ((TabsViewPagerFragmentActivity)activity).initialiseTabHost(null);

            ((TabsViewPagerFragmentActivity)activity).NotifyTabActivityViewPagerAdapter();

            }
        else
        {
            responseHandler.handleProcessSGRDLReportDataResult(result, activity);       
        }
    }
    else {
        processException();
    }
}

private void processException() {
    Toast.makeText(activity,   activity.getString(R.string.error_when_parsing_data), 3000).show();
}
}

答: 遵循@Luksprog对所有偶然发现相同问题的人的建议,这是对我有用的最终结果,在 AsyncTask 中我需要添加以下内容:

if (activity.getClass() == TabsViewPagerFragmentActivity.class)
{
                TabsViewPagerFragmentActivity tempActivity = ((TabsViewPagerFragmentActivity)activity);
                application.currentReport = result;
                Log.d(TAG, "Current report parsed is: "+result);
                List<Fragment> frags =  tempActivity.getTabActivityViewPagerAdapter().getFragments(); // getter method in your adapter
                FragmentTransaction ft = tempActivity.getSupportFragmentManager().beginTransaction();
                for (int i = 0; i < frags.size(); i++) 
                {
                    ft.remove(frags.get(i));
                }
                ft.commit(); 
                tempActivity.intialiseViewPager();
                tempActivity.getTabHost().getTabWidget().removeAllViews();
                tempActivity.initialiseTabHost(null);
                tempActivity.NotifyTabActivityViewPagerAdapter();
}

当主要的两点是从FragmentManager/中删除以前添加的片段时,SupportFragmentManager使用 aFragmentTransaction在中显示正确的片段集,并在添加新视图之前ViewPager从 中删除所有视图。TabWidget

4

3 回答 3

6

我不确定您是否解决了这个问题,如果是,请忽略我的回答。提供的链接Neron T很重要(更重要的是那里给出的建议不要引用外部适配器的片段)。

当您第二次使用新数据设置适配器时,由于实现方式,您将继续看到旧片段FragmentPagerAdapter。当您再次设置适配器时,适配器将首先运行将destroyItem()其片段. ViewPager接下来,适配器将运行该instantiateItem()方法。在此方法中,将对 执行检查FragmentManager以查看是否有任何先前的片段仍然不可用。此检查将找到旧片段(至少对于旧位置,这就是为什么您会获得新的位置片段,这些片段不在以前的情况下,当时没有任何片段),因为它们只是与ViewPager(但仍然可以FragmentManager通过findFragmentByTag())。FragmentManager 如果在only中找不到片段,getItem()则将调用该方法,从列表中检索片段。

您应该修改代码以删除对这些片段的列表引用,还有其他方法可以从中检索片段ViewPager(也不太理想)。作为快速修复,您可以尝试从FragmentManager(就在设置新适配器之前)手动删除旧片段以强制ViewPager.instantiateItem()方法始终调用getItem()

if (activity.getClass() == TabsViewPagerFragmentActivity.class) {
        application.currentReport = result;
        Log.d(TAG, "Current report parsed is: "+result);
        ListFragment<Fragment> frags = ((ViewPagerAdapter)mViewPager.getAdapter()).getFragments(); // getter method in your adapter
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    for (int i = 0; i < mOldTmp.size(); i++) {
    ft.remove(frags.get(i));
    }
    ft.commit(); 
        ((TabsViewPagerFragmentActivity)activity).intialiseViewPager();

        ((TabsViewPagerFragmentActivity)activity).initialiseTabHost(null);

        ((TabsViewPagerFragmentActivity)activity).NotifyTabActivityViewPagerAdapter();

        }

这未经测试,因此请尝试一下,看看它是否有效。

于 2013-06-15T09:45:08.520 回答
4

这个问题有2个解决方案:

解决方案 1 - 简单的 请参见此处:https ://stackoverflow.com/a/13467232/444324

基本上,您需要将此代码添加到您的 viewpager 适配器:

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

解决方案 2 - 推荐的解决方案在这里得到了很好的解释:https ://stackoverflow.com/a/8024557/444324

于 2013-06-09T09:08:30.850 回答
1

我将发布我的一些代码,以便您有所了解。

适配器初始化并将其设置为视图寻呼机。

vfPageContainer = (ViewPager)findViewById(R.id.vfPageContainer);
mAdapter = new TestFragmentAdapter(this,getSupportFragmentManager()); 
vfPageContainer.setAdapter(mAdapter);

每次新数据出现时,我都会调用以下方法:

updateUi() 方法

private void updateUi()
{   
    for(int i=0 ; i < alDataPages.size() ; i++)
    {
        mAdapter.addFragment(TestFragment.newInstance(this));
    }

    mAdapter.notifyDataSetChanged();
}

在 TestFragmentAdapter 类中,有 r 方法用于从视图寻呼机中添加和清除片段。

TestFragmentAdapter 类

class TestFragmentAdapter extends FragmentStatePagerAdapter {

    private Context context;

    private ArrayList<Fragment> views = new ArrayList<Fragment>();

    public TestFragmentAdapter(Context context,FragmentManager fm)
    {
        super(fm);

        this.context = context;

        views = new ArrayList<Fragment>();
    }

    @Override
    public Fragment getItem(int position)
    {
        return views.get(position);
    }

    public void addFragment (Fragment v)
    {
        views.add(v);
    }

    public void clear()
    {

        for(int i = 0 ; i < views.size() ; i++)
        {
            views.clear();
        }

    }

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


}

测试片段类

public final static class TestFragment extends Fragment {


    private Context context;

    public void setContext(Context c)
    {
        context = c;
    }

    public static TestFragment newInstance(Context context)
    {
        TestFragment f = new TestFragment();

        f.setContext(context);

        return f;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    {
        WebView webView_viewpage = new WebView(context);

        return webView_viewpage;
    }


}

所以当新数据出现之前我调用下面的代码。我正在从适配器中删除所有视图并创建新的 1 并将其设置为每次视图寻呼机。您还应该在您的代码中尝试它应该可以工作。

 mAdapter.clear(); // previously it was not working so i created new adapter and set it to the viewpager.
 mAdapter = new TestFragmentAdapter(this,getSupportFragmentManager()); 
 vfPageContainer.setAdapter(mAdapter);

希望这对您有所帮助,您会找到解决方案。

于 2013-06-15T09:36:30.427 回答