Fragmente scheinen sehr gut für die Trennung der UI-Logik in einige Module zu sein. Aber zusammen mit ViewPager
Sein Lebenszyklus ist mir immer noch schleierhaft. So Guru Gedanken sind dringend erforderlich!
bearbeiten
Siehe dumme Lösung unten ;-)
Umfang
Die Haupttätigkeit hat eine ViewPager
mit Fragmenten. Diese Fragmente können eine etwas andere Logik für andere (Submain) Aktivitäten implementieren, so dass die Daten der Fragmente über eine Callback-Schnittstelle innerhalb der Aktivität gefüllt werden. Und alles funktioniert gut beim ersten Start, aber!...
Problem
Wenn die Aktivität neu erstellt wird (z. B. bei einer Ausrichtungsänderung), werden auch die ViewPager
die Fragmente. Der Code (den Sie unten finden) besagt, dass ich jedes Mal, wenn die Aktivität erstellt wird, versuche, ein neues ViewPager
Fragmente Adapter das gleiche wie Fragmente (vielleicht ist dies das Problem), aber FragmentManager hat bereits alle diese Fragmente irgendwo gespeichert (wo?) und startet den Wiederherstellungsmechanismus für diese. Der Wiederherstellungsmechanismus ruft also die onAttach, onCreateView, etc. des "alten" Fragments mit meinem Callback-Interface-Aufruf zur Initiierung von Daten über die implementierte Methode der Activity auf. Aber diese Methode zeigt auf das neu erstellte Fragment, das über die onCreate-Methode der Activity erstellt wird.
Ausgabe
Vielleicht verwende ich die falschen Muster, aber selbst im Android 3 Pro Buch steht nicht viel darüber. Also, bitte Geben Sie mir einen doppelten Schlag und zeigen Sie mir, wie man es richtig macht. Vielen Dank!
Code
Haupttätigkeit
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 alias Hilfsprogramm
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 dumme Lösung ist, die Fragmente in onSaveInstanceState (der Host-Aktivität) mit putFragment zu speichern und sie in onCreate über getFragment abzurufen. Aber ich habe immer noch ein komisches 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();
...
}