按下后退按钮时正在重新创建 Listview 片段

Posted

技术标签:

【中文标题】按下后退按钮时正在重新创建 Listview 片段【英文标题】:Listview fragment is getting recreated on pressing backbutton 【发布时间】:2014-04-30 15:11:14 【问题描述】:

我在我的ListView 片段中使用了加载器,它在按下“返回”按钮时被重新创建。你能告诉我如何处理这种情况吗?

这是我的ListView 片段代码。在这里,我有一个布尔变量,我在单击列表项时将其设置为true。但是一旦按下后退按钮onCreateView 将被调用,因此后退按钮将为假。

public class GTFragment  extends SherlockFragment implements LoaderCallbacks<Cursor>

    ListView mTListview = null;
    GoogleTasksAdapter mGTasksAdapter = null;
    private SQLiteCursorLoader mTLoader=null;
    private LoaderManager mTLoaderManager;
    private String mSelectedListID = null; 
    private boolean mIsBackbuttonisPressed = false;

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

    View view = inflater.inflate(R.layout.task_home_activity, container, false);


    if(!mIsBackbuttonisPressed)
        getLoaderManager().initLoader(0, null, this);

     mTListview   = (ListView) view.findViewById(R.id.id_task_list_home_activity);

     mGTasksAdapter = new GoogleTasksAdapter(getActivity());

     mTListview.setOnItemClickListener(new OnItemClickListener() 

         @Override
         public void onItemClick(AdapterView<?> listview,
            View clickedview, int position, long arg3) 
            // TODO Auto-generated method stub

            GoogleTaskItem item = new GoogleTaskItem();

            Cursor coursor = ((GoogleTasksAdapter)listview.getAdapter()).getCursor();



            if(coursor.moveToPosition(position))
            


                mIsBackbuttonisPressed = true;
                GoogleTaskController.get_googletask_controllerObj()
                  .LaunchTaskPreviewActivity();                 
            

        

    );

   mTListview.setAdapter(mGTasksAdapter);  
   mIsBackbuttonisPressed = false;

   return view;

  

我的片段活动类代码

public class TLActivity extends SherlockFragmentActivity 

    LeftSliderTaskListOptions mTaskOptionsFragment = null;
    GoogleTasksFragment mTFragment = null;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);



        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);

        setContentView(R.layout.layout_gt_list);


//      FragmentTransaction tfragment = this.getSupportFragmentManager().beginTransaction();
        mTFragment = new GTasksFragment();
        t.replace(R.id.id_tfragment, mTFragment);
        t.commit();


    

【问题讨论】:

@NehaShukla,当你编辑帖子时,你应该尽可能地改进它。你在开头留下了几个错别字和明显的enter code here 是的,你对..会小心的 @NehaShukla,谢谢 :) 【参考方案1】:

而不是

t.replace(R.id.id_tfragment, mTFragment); 

使用

t.add(R.id.id_tfragment, mTFragment); 

它对我有用

【讨论】:

【参考方案2】:

我不认为接受的答案是正确的,因为 Fragment.onSaveInstanceState 在托管它需要保存其状态的活动之前不会被调用:docs 状态:

在很多情况下,片段可能大部分被拆除 (例如在没有显示 UI 的情况下放置在后堆栈上时),但它的 直到它拥有的活动实际上需要保存状态才会被保存 保存它的状态。

换句话说:如果您使用的 Activity 每个屏幕都有多个片段(这很常见),那么当您移动下一个屏幕时片段状态将不会被保存。

您也不能使用Fragment.setRetainInstance,因为他只适用于不在后台堆栈中的片段。

大多数时候,您不必考虑这一点,但有时它很重要。就像您滚动列表并想要“记住”滚动位置一样。

我花了很长时间才意识到放在后堆栈上的片段是一种保存的,您可以重用您已经创建的视图,而不是每次片段调用 onCreateView 时都创建一个。我的设置是这样的:

public abstract class BaseFragment extends Fragment 
     private boolean mSaveView = false;
     private SoftReference<View> mViewReference;

     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
          if (mSaveView) 
               if (mViewReference != null) 
                    final View savedView = mViewReference.get();
                    if (savedView != null) 
                         if (savedView.getParent() != null) 
                              ((ViewGroup) savedView.getParent()).removeView(savedView);
                              return savedView;
                         
                    
               
          

          final View view = inflater.inflate(getFragmentResource(), container, false);
          mViewReference = new SoftReference<View>(view);
          return view;
     

     protected void setSaveView(boolean value) 
           mSaveView = value;
     


public class MyFragment extends BaseFragment 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
          setSaveView(true);
          final View view = super.onCreateView(inflater, container, savedInstanceState);
          ListView placesList = (ListView) view.findViewById(R.id.places_list);
          if (placesList.getAdapter() == null)  // this check is important so you don't restart your adapter
               placesList.setAdapter(createAdapter());
          
     

【讨论】:

【参考方案3】:

您有多种选择来纠正此问题。

    像这样覆盖 onSaveInstanceState:

    @Override
    public void onSaveInstanceState (Bundle outState) 
        super.onSaveInstanceState(outState);
        outState.putBoolean("mIsBackbuttonisPressed", mIsBackbuttonisPressed);
    
    

    然后在您的 onCreateView 中,您可以通过以下方式取回您的变量:

    if (savedInstanceState != null)
        mIsBackbuttonisPressed = savedInstanceState.getBoolean("mIsBackbuttonisPressed", false);
    

    您可以在片段的 onCreate 方法中设置this.setRetainInstance(true);

如果您可以通过创建片段发布您的活动代码,我还可以告诉您其他选项。 (PS 我不能把它写成评论,所以把它贴在答案里。)

【讨论】:

嗨,谢谢你的回答,当我按下后退按钮时,我的整个片段活动本身正在重新创建,我会给你提供片段活动的完整代码。 您好代码已更新,请您帮忙。我在单击任务列表项时创建新活动。一旦我回击,我注意到我的片段活动正在重新创建,我认为它是错误的,不知道是什么错误,如果我可以避免这种情况,那么我的问题将得到解决,希望如此。你能给我建议吗 你能检查一下在你按下后是否调用了 TLActivity onCreate 吗?原因可能是系统正在破坏您的活动。 Documentation 谢谢,我非常接近解决方案,还有一个问题,如果我按下后退按钮,那么我是否必须重新加载列表视图上的光标?信息不会存储在缓存中吗? 是的,您必须在 onCreate 中重新加载光标,因为如果 Activity 或 Fragment 被销毁,那么适配器也必须重新加载。

以上是关于按下后退按钮时正在重新创建 Listview 片段的主要内容,如果未能解决你的问题,请参考以下文章

如何确定后退按钮按下

使用导航控制器按下后退按钮后,如何防止先前的片段出现?

如何在按下单个片段的手动后退按钮时返回上一个片段?

替换两个不同的片段后,按下后​​退按钮时会重新创建第一个片段

如何防止在android片段中按下后退按钮时调用onCreateView

使用导航控制器按下后退按钮后如何防止前一个片段显示?