0
votes

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

ATabs fragment

After I switch between ATabs and B using navigation drawer, add item (+) gets displayed but has no effect on fragment A1.

nav drawer, frag B, not able to add

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.

1
I also noticed that the action bar title is MyApp first. Also when I switch between fragment A1 and A2. But once I use the navigation drawer to switch between fragment B and back to ATabs, the action bar displays A1.evolved
Use getChildFragmentManager() instead of getFragmentManager() in ATabs.user
Thank you so much! This solved my problem!evolved
Can you tell me why adding items is working in the first place but after switching between fragments using the nav drawer it needs getChildFragmentManager()?evolved
If you use nested fragments(fragments inside fragments) you need to use getChildFragmentManager(). Otherwise the activity FragmentManager might initially work but as soon as you manipulate those fragments things will go wrong.user

1 Answers

1
votes

Thanks to @Luksprog the main Problem is solved by using getChildFragmentManager() instead of FragmentManager() inside ATabs.