首页 文章

Android Fragment创建了两次方向更改

提问于
浏览
5

我的片段被创建了两次,即使活动仅将片段添加到内容中一次 . 旋转屏幕时会发生这种情况 . 此外,每次调用片段的onCreateView时,它都会丢失所有可变状态 .

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) { // Checking for recreation
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new AppPanelFragment())
                    .commit();
        }
    }

}

onCreate在活动中检查null savedInstanceState,并且只有null将添加片段,所以我不明白为什么片段应该被创建两次?在if条件中设置断点告诉我它只被调用一次,因此活动不应该多次添加片段 . 但是,每次方向更改时,仍然会调用片段的onCreateView .

public class AppPanelFragment extends Fragment {

            private TextView appNameText;

            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) {
// This method called several times
                View rootView = inflater.inflate(R.layout.fragment_app_panel, container, false);

// 2nd call on this method, appNameText is null, why?
appNameText = (TextView) rootView.findViewById(R.id.app_name);
appNameText.text = "My new App";

    return view;

    }

我设法使用setRetainInstance(true)保持变量状态,但这是真正的解决方案吗?我希望片段不会仅仅在方向改变时创建 .

4 回答

  • 0

    在android中,当手机的方向改变时,活动将被销毁并重新创建 . 现在,我相信要解决您的问题,您可以使用片段管理器检查片段是否已经存在于后端堆栈中,如果它不存在则创建它 .

    public void onCreated(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if (savedInstanceState == null) {
                mFragmentManager = getSupportFragmentManager();
                AppPanelFragment fragment  = (AppPanelFragment)mFragmentManager.findFragmentById(R.id.fagment_id);
                if(fragment == null) {
                    //do your fragment creation
                } 
            }
        }
    

    附:我没有测试过这个,但是一旦你在findFragmentById方法中提供了正确的片段id,它就应该可以工作了 .

  • 3

    Fragment 生命周期与 Activity 非常相似 . 默认情况下,是的,它们将在配置更改期间重新创建,就像 Activity 一样 . 这是预期的行为 . 即使使用了 setRetainInstance(true) (我会说如果它包含一个UI我会非常谨慎地使用),你的 View 将被销毁并重新创建,但在这种情况下你的 Fragment 实例不会被销毁 - 只有 View .

  • 0

    如上所述,在方向更改时,活动将被销毁并重新创建 . 此外,系统会重新创建片段(任何) .

    为确保应用程序恢复到以前的状态,在销毁活动之前调用onSaveInstanceState() .

    因此,您可以在活动的onSaveInstanceState()方法中存储一些信息,然后在方向更改时将应用程序恢复到相同的状态 .

    注意:您不需要在方向更改时创建片段,因为会重新创建片段 .

    http://www.mynewsfeed.x10.mx/articles/index.php?id=15中的示例:

    public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        if ( savedInstanceState == null ){
              //Initialize fragments
              Fragment example_fragment = new ExampleFragment();
              FragmentManager manager = getFragmentManager();
              FragmentTransaction transaction = manager.beginTransaction();
              transaction.add(R.id.container, example_fragment, "Example");
        } else{
           //control comes to this block only on orientation change.
    
           int postion = savedInstanceState.getInt("position"); //You can retrieve any piece of data you've saved through onSaveInstanceState()
    
          //finding fragments on orientation change 
          Fragment example_fragment = manager.findFragmentByTag("Example");
    
         //update the fragment so that the application retains its state
         example_fragment.setPosition(position); //This method is just an example
    
        }
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("position", position); //add any information you'd like to save and restore on orientation change.
        }
    
    }
    
  • 4

    我知道回答有点迟,但使用The Code Pimp回答你可以做下一件事:

    如果片段存在于backstack中,我们会弹出并将其删除以将其添加回来(如果在不删除它的情况下将其添加回来,则会抛出异常,说它已经存在) .

    fragment变量是一个类成员变量 .

    此方法将在Activity的onCreate方法中调用:

    if (savedInstanceState == null) {
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            if (fragmentManager.findFragmentById(getFragmentActivityLayoutContainerId()) == null) {
                fragment = getNewFragmentInstance();
            } else {
                fragment = fragmentManager.findFragmentById(getFragmentActivityLayoutContainerId());
                fragmentTransaction.remove(fragment);
                fragmentManager.popBackStack();
                fragmentTransaction.commit();
                fragmentTransaction = fragmentManager.beginTransaction();
            }
            fragmentTransaction.add(getFragmentActivityLayoutContainerId(), fragment);
            fragmentTransaction.commit();
        }
    

    下一个代码将在片段本身中调用 .

    这是您可以在片段中实现的代码的一个小示例,以了解它的工作原理 . dummyTV是片段中心的简单文本视图,它根据方向接收文本(为此我们需要一个计数器) .

    private TextView dummyTV;
    private static int counter = 0;
    
    @Override
    protected int getFragmentLayoutId() {
        return R.layout.fragment_alerts_view;
    }
    
    @Override
    protected void saveReferences(View view) {
        dummyTV = (TextView) view.findViewById(R.id.fragment_alerts_view_dummy_tv);
    }
    
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
    
        if (savedInstanceState != null) {
            dummyTV.setText(savedInstanceState.getString("dummy_string"));
        } else {
            dummyTV.setText("flip me!");
        }
    
        dummyTV.append(" | " + String.valueOf(counter));
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString("dummy_string", counter++ % 2 == 0 ? "landscape" : "portrait");
    }
    

相关问题