Fragmentos parecem muito bons para a separação da lógica da interface do usuário em alguns módulos. Mas junto com o ViewPager
seu ciclo de vida ainda é nebuloso para mim. Portanto, os pensamentos do Guru são extremamente necessários!
Editar
Veja a solução burra abaixo ;-)
Escopo
Atividade principal ViewPager
com fragmentos. Esses fragmentos podem implementar uma lógica um pouco diferente para outras atividades (subdomínios), para que os dados dos fragmentos sejam preenchidos por meio de uma interface de retorno de chamada dentro da atividade. E tudo funciona bem no primeiro lançamento, mas! ...
Problema
Quando a atividade é recriada (por exemplo, na mudança de orientação), o mesmo ocorre com os ViewPager
fragmentos. O código (você encontrará abaixo) diz que toda vez que a atividade é criada, tento criar um novo ViewPager
adaptador de fragmentos igual aos fragmentos (talvez esse seja o problema), mas o FragmentManager já possui todos esses fragmentos armazenados em algum lugar (onde?) E inicia o mecanismo de recreação para aqueles. Portanto, o mecanismo de recreação chama onAttach, onCreateView, etc. do fragmento "antigo", com minha interface de retorno de chamada, para iniciar dados por meio do método implementado da Activity. Mas esse método aponta para o fragmento recém-criado, criado pelo método onCreate da Activity.
Questão
Talvez eu esteja usando padrões errados, mas mesmo o livro do Android 3 Pro não tem muito a ver. Então, por favor , me dê um soco de um a dois e aponte como fazê-lo da maneira certa. Muito Obrigado!
Código
Atividade principal
public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener {
private MessagesFragment mMessagesFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
Logger.d("Dash onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_container);
new DefaultToolbar(this);
// create fragments to use
mMessagesFragment = new MessagesFragment();
mStreamsFragment = new StreamsFragment();
// set titles and fragments for view pager
Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>();
screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment());
screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment);
// instantiate view pager via adapter
mPager = (ViewPager) findViewById(R.id.viewpager_pager);
mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
// set title indicator
TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles);
indicator.setViewPager(mPager, 1);
}
/* set of fragments callback interface implementations */
@Override
public void onMessageInitialisation() {
Logger.d("Dash onMessageInitialisation");
if (mMessagesFragment != null)
mMessagesFragment.loadLastMessages();
}
@Override
public void onMessageSelected(Message selectedMessage) {
Intent intent = new Intent(this, StreamActivity.class);
intent.putExtra(Message.class.getName(), selectedMessage);
startActivity(intent);
}
Auxiliar de BasePagerActivity aka
public class BasePagerActivity extends FragmentActivity {
BasePagerAdapter mPagerAdapter;
ViewPager mPager;
}
Adaptador
public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider {
private Map<String, Fragment> mScreens;
public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) {
super(fm);
this.mScreens = screenMap;
}
@Override
public Fragment getItem(int position) {
return mScreens.values().toArray(new Fragment[mScreens.size()])[position];
}
@Override
public int getCount() {
return mScreens.size();
}
@Override
public String getTitle(int position) {
return mScreens.keySet().toArray(new String[mScreens.size()])[position];
}
// hack. we don't want to destroy our fragments and re-initiate them after
@Override
public void destroyItem(View container, int position, Object object) {
// TODO Auto-generated method stub
}
}
Fragmento
public class MessagesFragment extends ListFragment {
private boolean mIsLastMessages;
private List<Message> mMessagesList;
private MessageArrayAdapter mAdapter;
private LoadMessagesTask mLoadMessagesTask;
private OnMessageListActionListener mListener;
// define callback interface
public interface OnMessageListActionListener {
public void onMessageInitialisation();
public void onMessageSelected(Message selectedMessage);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// setting callback
mListener = (OnMessageListActionListener) activity;
mIsLastMessages = activity instanceof DashboardActivity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
inflater.inflate(R.layout.fragment_listview, container);
mProgressView = inflater.inflate(R.layout.listrow_progress, null);
mEmptyView = inflater.inflate(R.layout.fragment_nodata, null);
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// instantiate loading task
mLoadMessagesTask = new LoadMessagesTask();
// instantiate list of messages
mMessagesList = new ArrayList<Message>();
mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList);
setListAdapter(mAdapter);
}
@Override
public void onResume() {
mListener.onMessageInitialisation();
super.onResume();
}
public void onListItemClick(ListView l, View v, int position, long id) {
Message selectedMessage = (Message) getListAdapter().getItem(position);
mListener.onMessageSelected(selectedMessage);
super.onListItemClick(l, v, position, id);
}
/* public methods to load messages from host acitivity, etc... */
}
Solução
A solução idiota é salvar os fragmentos dentro de onSaveInstanceState (da atividade do host) com putFragment e colocá-los dentro de onCreate via getFragment. Mas ainda tenho uma sensação estranha de que as coisas não devem funcionar assim ... Veja o código abaixo:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager()
.putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment);
}
protected void onCreate(Bundle savedInstanceState) {
Logger.d("Dash onCreate");
super.onCreate(savedInstanceState);
...
// create fragments to use
if (savedInstanceState != null) {
mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment(
savedInstanceState, MessagesFragment.class.getName());
StreamsFragment.class.getName());
}
if (mMessagesFragment == null)
mMessagesFragment = new MessagesFragment();
...
}