Fragmente scheinen sehr schön für die Aufteilung der UI-Logik in einige Module zu sein. Aber zusammen mit ViewPager
seinem Lebenszyklus ist für mich immer noch neblig. Guru-Gedanken werden also dringend benötigt!
Bearbeiten
Siehe dumme Lösung unten ;-)
Umfang
Hauptaktivität hat eine ViewPager
mit Fragmenten. Diese Fragmente könnten eine etwas andere Logik für andere (Haupt-) Aktivitäten implementieren, sodass die Daten der Fragmente über eine Rückrufschnittstelle innerhalb der Aktivität gefüllt werden. Und beim ersten Start funktioniert alles einwandfrei, aber! ...
Problem
Wenn die Aktivität neu erstellt wird (z. B. bei einer Änderung der Ausrichtung), tun dies auch die ViewPager
Fragmente der Aktivität . Der Code (den Sie unten finden) besagt, dass ich jedes Mal, wenn die Aktivität erstellt wird, versuche, einen neuen ViewPager
Fragmentadapter zu erstellen, der mit Fragmenten identisch ist (möglicherweise ist dies das Problem), aber FragmentManager hat bereits alle diese Fragmente irgendwo gespeichert (wo?) Und startet den Erholungsmechanismus für diese. Der Wiederherstellungsmechanismus ruft also onAttach, onCreateView usw. des "alten" Fragments mit meinem Aufruf der Rückrufschnittstelle auf, um Daten über die implementierte Methode der Aktivität zu initiieren. Diese Methode verweist jedoch auf das neu erstellte Fragment, das über die onCreate-Methode der Aktivität erstellt wird.
Problem
Vielleicht verwende ich falsche Muster, aber selbst das Android 3 Pro-Buch hat nicht viel damit zu tun. Also, bitte , gib mir einen Doppelsieg und zeige, wie es richtig geht. Danke vielmals!
Code
Hauptaktivität
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);
}
BasePagerActivity aka Helfer
public class BasePagerActivity extends FragmentActivity {
BasePagerAdapter mPagerAdapter;
ViewPager mPager;
}
Adapter
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
}
}
Fragment
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... */
}
Lösung
Die blöde Lösung besteht darin, die Fragmente in onSaveInstanceState (der Host-Aktivität) mit putFragment zu speichern und sie über getFragment in onCreate abzurufen. Aber ich habe immer noch das seltsame Gefühl, dass die Dinge nicht so funktionieren sollten ... Siehe Code unten:
@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();
...
}