Edit: There seems to be a problem with my sliding tabs fragment ATabs. Without using the ATabs fragment and just switching between fragment A1 and B using the navigation drawer, everything works fine! Adding ListItems is possible. Edited MainActivity:
@Override
public void onNavigationDrawerItemSelected(int position) {
mFragment = null;
switch (position) {
case 0:
mFragment = A1.newInstance(position + 1, this);
break;
case 1:
mFragment = B.newInstance(position + 1);
break;
}
onSectionAttached(position);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, mFragment)
.commit();
mFragment = null;
}
But as soon as I use the ATabs fragment (see MainActivity below) and switched to it and back, adding ListItems isn't possible anymore. Though Logcat shows Log.v(LOG_TAG, "Added Item");
everytime I press add (+).
I have no idea what causes the problem. If the ATabs needs to be an Activity instead a Fragment or if my PagerAdapter is causing the problem. In my ATabs class tried using the two different PagerAdapters:
public static class MyAdapter extends FragmentStatePagerAdapter {
...
}
and
public static class MyAdapter extends FragmentPagerAdapter {
...
}
The latter even caused the whole fragments not do display properly and the switching between the tabs wasn't possible too.
I have a navigation drawer that displays two different fragments ATabs and B.
Fragment ATabs contains two sliding tabs. Each tab holds another Fragment A1 and A2. Until now A2 and B are just empty fragments with a simple TextView, so basically the same A2 = B. Fragment A1 has a ListView
with some predefined EditText
items when the app starts. The user can add additional EditText Items by pressing on add inside the "custom" action bar for this particular fragment (A1).
In general fragment A1 should have different action bar items than fragment A2 and B. This seems to work already. For that I added set setHasOptionsMenu(true);
to each fragment, override the onCreateOptionsMenu
method including menu.clear()
and setting the desired menu from the resources.
Here is already my first question: Is it necessary to do this inside all fragments that would use the default main activity action bar anyway?
And my main problem is adding additional items to the list view:
When I switch between the initial fragment A1 - displayed when the app starts - to fragment A2 and back to A1 inside ATabs fragment everything works fine. I can add additional items and previous added items are also still visible. But once I switched between fragment B and A1 using the navigation drawer I cannot add any items anymore and also don't see my previously added items. I will use a database later to store my items but it should be still possible to add additional items as before.
Here are some screens to better demonstrate my problem:
App starts with A1 fragment, switching between A1 and A2, adding is possible with + item
After I switch between ATabs and B using navigation drawer, add item (+) gets displayed but has no effect on fragment A1.
Here is my MainActivity that holds the navigation drawer:
I am not really sure if the switching inside onNavigationDrawerItemSelected
between the fragments is correct or if I create new fragments everytime I switch. Is Android deleting the previous fragment or is this causing a memory overflow after multiple switching? And my "first" A1 fragment is still "hidden behind" the newly created ones?
I am quite new to Android and I really don't see why I cannot add any items after I switched between navigation drawer fragments.
public class MainActivity extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks, A1.OnFragmentInteractionListener, A2.OnFragmentInteractionListener, B.OnFragmentInteractionListener {
private NavigationDrawerFragment mNavigationDrawerFragment;
private CharSequence mTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = ATabs.newInstance(position + 1, this);
break;
case 1:
fragment = B.newInstance(position + 1);
break;
}
onSectionAttached(position);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
public void onSectionAttached(int number) {
switch (number+1) {
case 1:
mTitle = getString(R.string.title_ATabs);
break;
case 2:
mTitle = getString(R.string.title_B);
break;
}
}
public void restoreActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onFragmentInteraction(Uri uri) {
}
}
Fragment ATabs with the sliding tabs:
public class ATabs extends Fragment {
static final String LOG_TAG = "ATabs";
private static final String ARG_PARAM1 = "param1";
private static Context mContext;
private SlidingTabLayout mSlidingTabLayout;
private ViewPager mViewPager;
public static ATabs newInstance(int sectionNumber, Context context) {
ATabs fragment = new ATabs();
mContext = context;
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.main, menu);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_atabs, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
mViewPager.setAdapter(new MyAdapter(getFragmentManager()));
mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
mSlidingTabLayout.setViewPager(mViewPager);
}
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return 2;
}
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = A1.newInstance(position, mContext);
break;
case 1:
fragment = A2.newInstance(position);
break;
}
return fragment;
}
@Override
public CharSequence getPageTitle(int position) {
CharSequence pageTitle = "NOT SET";
switch (position) {
case 0:
pageTitle = "A1 Tab";
break;
case 1:
pageTitle = "A2 Tab";
break;
}
return pageTitle;
}
}
}
As already asked: Is it necessary to call setHasOptionsMenu(true)
and override onCreateOptionsMenu()
inside fragments that would use the default main activity action bar?
Here is Fragment A2 (same as class B) using the default main activity action bar:
public class A2 extends Fragment {
private static final String ARG_PARAM1 = "param1";
private String mParam1;
private OnFragmentInteractionListener mListener;
public static A2 newInstance(int sectionNumber) {
A2 fragment = new A2();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public A2() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
}
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.main, menu);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a2, container, false);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
}
Fragment A1 uses its own a1 action bar menu: The additional add item.
public class A1 extends Fragment {
private static final String ARG_PARAM1 = "param1";
private final String LOG_TAG = A1.class.getSimpleName();
private ArrayAdapter<String> mForecastAdapter;
private static Context mContext = null;
private ListView myList;
private MyAdapter myAdapter;
private String mParam1;
private OnFragmentInteractionListener mListener;
public static A1 newInstance(int sectionNumber, Context context) {
A1 fragment = new A1();
mContext = context;
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public A1() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
}
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.a1, menu);
}
public ArrayList myItems = new ArrayList();
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle item selection
switch (item.getItemId()) {
case R.id.action_add_item:
ListItem listItem = new ListItem();
listItem.caption = "Added Item";
myItems.add(listItem);
Log.v(LOG_TAG, "Added Item");
myAdapter.notifyDataSetChanged();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public MyAdapter() {
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < 3; i++) {
ListItem listItem = new ListItem();
listItem.caption = "Caption" + i;
myItems.add(listItem);
}
notifyDataSetChanged();
}
public int getCount() {
return myItems.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.list_item_a1, null);
holder.caption = (EditText) convertView
.findViewById(R.id.list_item_a1_edit_text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//Fill EditText with the value you have in data source
ListItem item = (ListItem) myItems.get(position);
holder.caption.setText(item.caption);
holder.caption.setId(position);
//we need to update adapter once we finish with editing
holder.caption.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus){
final int position = v.getId();
final EditText Caption = (EditText) v;
ListItem item = (ListItem) myItems.get(position);
item.caption = Caption.getText().toString();
}
}
});
return convertView;
}
}
class ViewHolder {
EditText caption;
}
class ListItem {
String caption;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_a1, container, false);
// Get a reference to the ListView, and attach this adapter to it.
myList = (ListView) rootView.findViewById(R.id.listview_a1);
myList.setItemsCanFocus(true);
myAdapter = new MyAdapter();
myList.setAdapter(myAdapter);
return rootView;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
public void onFragmentInteraction(Uri uri);
}
}
And finally the action bar menus: main:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item
android:id="@+id/action_example"
android:title="@string/action_example"
app:showAsAction="never" />
<item
android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
app:showAsAction="never" />
<item
android:id="@+id/action_help"
android:title="@string/action_help"
android:orderInCategory="100"
app:showAsAction="never" />
</menu>
a1:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item
android:id="@+id/action_add_item"
android:title="@string/action_add_item"
android:icon="@drawable/ic_action_new"
app:showAsAction="always" />
<item
android:id="@+id/action_example"
android:title="@string/action_example"
app:showAsAction="never" />
<item
android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
app:showAsAction="never" />
<item
android:id="@+id/action_help"
android:title="@string/action_help"
android:orderInCategory="100"
app:showAsAction="never" />
</menu>
Please let me know if any other code is needed to solve my problem.
getChildFragmentManager()
instead ofgetFragmentManager()
in ATabs. – usergetChildFragmentManager()
? – evolved