Maneira infalível de lidar com o fragmento na mudança de orientação

87
public class MainActivity extends Activity implements MainMenuFragment.OnMainMenuItemSelectedListener {

 @Override
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager
            .beginTransaction();

    // add menu fragment
    MainMenuFragment myFragment = new MainMenuFragment();
    fragmentTransaction.add(R.id.menu_fragment, myFragment);

    //add content
    DetailPart1 content1= new DetailPart1 ();
    fragmentTransaction.add(R.id.content_fragment, content1);
    fragmentTransaction.commit();

}
public void onMainMenuSelected(String tag) {
  //next menu is selected replace existing fragment
}

Preciso exibir duas visualizações de lista lado a lado, menu à esquerda e seu conteúdo à direita. Por padrão, o primeiro menu é selecionado e seu conteúdo é exibido no lado direito. O fragmento que exibe o conteúdo é o seguinte:

public class DetailPart1 extends Fragment {
  ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
  ListAdapter adap;
  ListView listview;

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

       if(savedInstanceState!=null){
        myList = (ArrayList)savedInstanceState.getSerializable("MYLIST_obj");
        adap = new LoadImageFromArrayListAdapter(getActivity(),myList );
        listview.setAdapter(adap);
       }else{
        //get list and load in list view
        getlistTask = new GetALLListTasks().execute();
    }


     @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.skyview_fragment, container,false);
           return v;
        }


     @Override
      public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
          outState.putSerializable("MYLIST_obj", myList );
        }
    }

OnActivityCreated e onCreateView são chamados duas vezes . Existem muitos exemplos por aí usando fragmentos. Como sou iniciante neste assunto, não consigo relacionar o exemplo com o meu problema. Preciso de uma maneira infalível de lidar com a mudança de orientação. Eu NÃO declarei android:configChangesno arquivo de manifesto. Preciso que a atividade seja destruída e recriada para que possa usar um layout diferente no modo paisagem.

user1811741
fonte
Normalmente, as mudanças na orientação dos fragmentos são feitas sem que você precise fazer nada. Então, qual é o problema que você enfrenta ao mudar a orientação?
Alexander Kulyakhtin
Alex, preciso do fragmento da classe DetailPart1 para exibir o layout com listView no modo retrato e o layout com Grid View no modo paisagem. Para isso, preciso recriar o fragmento todas as vezes, mas não quero carregar os mesmos registros novamente, então eu armazene-os em onSaveInstanceState. Mas o código acima recria DetailPart1 duas vezes, preciso saber o código ausente que o faz funcionar como desejado
user1811741
possível duplicação do ciclo de vida do fragmento
naXa

Respostas:

132

Você está criando um novo fragmento cada vez que vira a tela em sua atividade. onCreate();Mas também está mantendo os antigos com super.onCreate(savedInstanceState);. Então, talvez defina a tag e encontre o fragmento, se ele existir, ou passe o pacote nulo para super.

Isso me levou um tempo para aprender e pode ser realmente uma merda quando você está trabalhando com coisas como o viewpager.

Eu recomendo que você leia sobre fragmentos mais uma vez, já que este tópico exato é abordado.

Aqui está um exemplo de como lidar com fragmentos em uma mudança de orientação regular:

Atividade :

public class MainActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            TestFragment test = new TestFragment();
            test.setArguments(getIntent().getExtras());
            getSupportFragmentManager().beginTransaction().replace(android.R.id.content, test, "your_fragment_tag").commit();
        } else {
            TestFragment test = (TestFragment) getSupportFragmentManager().findFragmentByTag("your_fragment_tag");
        }
    }
}

Fragmento :

public class TestFragment extends Fragment {

    public static final String KEY_ITEM = "unique_key";
    public static final String KEY_INDEX = "index_key";
    private String mTime;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);

        if (savedInstanceState != null) {
            // Restore last state
            mTime = savedInstanceState.getString("time_key");
        } else {
            mTime = "" + Calendar.getInstance().getTimeInMillis();
        }

        TextView title = (TextView) view.findViewById(R.id.fragment_test);
        title.setText(mTime);

        return view;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("time_key", mTime);
    }
}
Warpzit
fonte
obrigado Warpzit por seu esforço, mas ficarei feliz se você explicar em código sobre seu ponto. Como alterar meu código para lidar com a mudança de orientação sem recarregar o fragmento.
user1811741
1
Portanto, preciso alterar o layout do fragmento na orientação, mas não quero recarregar todos os registros, o que fiz foi 1. Adicionar android: configchanges = "orientação" no manifesto 2. substituir onConfigurationChanged no fragmento e detectar a orientação e ocultar / mostrar listview ou gridview dependendo da orientação. Este é o caminho certo?
user1811741
@ user1811741 atualizado com exemplo. Espero que esclareça tudo.
Warpzit de
@Warpzit Como pode lidar com o mesmo cenário no caso de implementação do fragmento ViewPager, já que o ViewPager cuida de todos os fragmentos exibidos ... qualquer sugestão.
CoDe
1
@Shubh bem, acredito que o viewpager lida com isso corretamente, se não, você terá que substituir a implementação getItem para atender às suas necessidades. Espero que tenha apontado a direção certa, se não colocar uma pergunta adequada :)
Warpzit
21

Uma boa orientação sobre como reter os dados entre as mudanças de orientação e a recreação da atividade pode ser encontrada nas diretrizes do Android .

Resumo:

  1. faça com que seu fragmento seja retido:

    setRetainInstance(true);
  2. Crie um novo fragmento apenas se necessário (ou, pelo menos, obtenha dados dele)

    dataFragment = (DataFragment) fm.findFragmentByTag("data");
    
    // create the fragment and data the first time
    if (dataFragment == null) {
    
Sergej Werfel
fonte
nice Economize meu tempo wah
Arjun saini