genechunlee
genechunlee

Reputation: 51

Android Replace Fragment in View Pager

I'm new to Android development and Java outside of simple JavaScripts for web pages. I've created a view pager that displays three different fragments. For the second fragment, BooksFragment, I use a grid view to display a grid of buttons that when the user presses should replace BooksFragment with another view.

The problem I run into is that although I'm using .replace() to replace the fragment, the second fragment just shows up on top of the original. Now, I've searched my problem extensively and I believe the reason that usually happens is when the original fragment is not created dynamically. Being the noob that I am, it does seem like I AM creating the fragments dynamically but I could be mistaken (I'm not using any tags in any of my XML files). Can anyone please help me out? My code is below:

MainActivity.java

import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.ActionBar;
import android.support.v4.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.app.FragmentManager;

public class MainActivity extends FragmentActivity implements
ActionBar.TabListener {

    // strings for tabs
    private ViewPager viewPager;
    private TabsPagerAdapter mAdapter;
    private ActionBar actionBar;
    // tab titles
    private String[] tabs = {"Status",
                            "Schedule",
                            "Books"};



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // Initialization
        viewPager = (ViewPager) findViewById(R.id.pager);
        actionBar = getActionBar();
        mAdapter = new TabsPagerAdapter(getSupportFragmentManager());

        viewPager.setAdapter(mAdapter);
        //actionBar.setHomeButtonEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Adding Tabs
        for (String tab_name : tabs) {
            actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
        }

        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                // on changing the page
                // make respected tab selected
                actionBar.setSelectedNavigationItem(position);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {

            }
        });


        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.pager, new PlaceholderFragment()).commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @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();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container,
                    false);
            return rootView;
        }
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // on tab selected
                // show respected fragment view
                viewPager.setCurrentItem(tab.getPosition());

    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        // TODO Auto-generated method stub
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        // TODO Auto-generated method stub
    }
}

TabsPagerAdapter.java

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;


public class TabsPagerAdapter extends FragmentPagerAdapter{

     public TabsPagerAdapter(FragmentManager fm) {
        super(fm);
     }

     @Override
     public Fragment getItem(int index) {

         switch (index) {
         case 0:
             // First fragment activity
             return new StatusFragment();
         case 1:
             // Second fragment activity
             return new ScheduleFragment();
         case 2:
             // Third fragment activity
             return new BooksFragment();
         }

         return null;
     }

     @Override
     public int getCount() {
         // get item count - equal to number of tabs
         return 3;
     }
}

BooksFragment.java

import java.util.ArrayList;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;


public class BooksFragment extends Fragment implements OnClickListener {

    // get database data
    private static final String DB_NAME = "bookReadingTracker";
    private static final String TABLE_NAME = "book_names";
    private static final String BOOK_NAME_ID = "_id";
    private static final String BOOKNAME = "bookname";
    private static final String BOOKABBR = "bookabbr";

    private SQLiteDatabase database;
    private ArrayList<String> allbooksabbr;

    private OnItemSelectedListener listener;

    GridView gridView;

    public static BooksFragment newInstance() {
        BooksFragment f = new BooksFragment();
        return f;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        ExternalDbOpenHelper dbOpenHelper = new ExternalDbOpenHelper(getActivity(), DB_NAME);
        database = dbOpenHelper.openDataBase();

        fillAllbooksabbr();

        View view = inflater.inflate(R.layout.books_fragment, container, false);

        gridView = (GridView) view.findViewById(R.id.gridviewBooks);

        gridView.setAdapter(new MyAdapter(getActivity(), allbooksabbr));

        gridView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View v,
                    int position, long id) {    


                ///////////////////

                Fragment chapterDetailFragment = ChaptersFragment.newInstance();
                FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
                transaction.addToBackStack(null);
                transaction.replace(R.id.booksFragmentHolder, chapterDetailFragment).commit();

                /////////////////////


            }
        });
        return view;
    }


    private void fillAllbooksabbr() {
        allbooksabbr = new ArrayList<String>();

        Cursor allbooksabbrCursor = database.query(TABLE_NAME, new String[] {BOOK_NAME_ID, BOOKABBR}, 
                                                    null, null, null, null, "CAST (" + BOOK_NAME_ID + " AS INTEGER)");
        allbooksabbrCursor.moveToFirst();
        if(!allbooksabbrCursor.isAfterLast()) {
            do {
                String bookabbr_array = allbooksabbrCursor.getString(1);
                allbooksabbr.add(bookabbr_array);
            } while (allbooksabbrCursor.moveToNext());
        }
        allbooksabbrCursor.close();
    }


    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

    }
}

MyAdapter.java

import java.util.ArrayList;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;


public class MyAdapter extends BaseAdapter {

    private Context context;
    private ArrayList<String> allbooksabbr;

    public MyAdapter(Context context, ArrayList<String> allbooksabbr) {
        this.context = context;
        this.allbooksabbr = allbooksabbr;
    }
    public View getView(int position, View convertView, ViewGroup parent) {

        View gridView;

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            gridView = inflater.inflate(R.layout.books_button, null);
        } else {
            gridView = (View) convertView;
        }

        //gridView = new View(context);
        gridView.setBackgroundColor(0xff645C69);
        TextView bookButton = (TextView) gridView.findViewById(R.id.bookbutton);
        bookButton.setText(allbooksabbr.get(position));

        return gridView;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return allbooksabbr.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return 0;
    }
}

Here are my XML files:

fragment_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.gclapps.bookreadingscheduletracker.MainActivity$PlaceholderFragment" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

books_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/booksFragmentHolder"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp" >

    <TextView
        android:id="@+id/textViewBooks"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Books" 
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="#666666"
        android:paddingTop="10dp"
        android:paddingBottom="5dp" />

     <GridView
         android:id="@+id/gridviewBooks"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:columnWidth="60dp"
         android:gravity="center"
         android:numColumns="auto_fit"
         android:stretchMode="columnWidth"
         android:verticalSpacing="2dp"
         android:horizontalSpacing="2dp" >
     </GridView>
</FrameLayout>

Please help me find the reason why my BooksFragment view doesn't get replaced with my ChaptersFragment view. If the BooksFragment view is indeed not created dynamically, please help me do so. I've read the documentation on how to do it, but am not able to figure out how to do it in my case with using the viewpager. Thanks!

Upvotes: 1

Views: 1976

Answers (1)

Gak2
Gak2

Reputation: 2701

Ok so after a quick look through your code, I noticed you used getChildFragmentManager() here:

FragmentTransaction transaction = getChildFragmentManager().beginTransaction();

getChildFragmentManager() manages fragments that are children of the current fragment. So when you call replace() , it doesn't actually remove the displayed BookFragment since it is not a child of the current fragment (the current fragment IS the BookFragment).

So normally to replace the fragment, I'd call getSupportFragmentManager() to get the right manager, but since you're using a ViewPager it makes things more difficult. You'd probably need to somehow change the ViewPager adapter on gridview item click with a new adapter that returns ChapterDetailFragment in its getItem() method.

You might be able to do something like this:

public class TabsPagerAdapter extends FragmentPagerAdapter{
    private boolean isChapterDetailShowing;
    private int chapter;

    public TabsPagerAdapter(FragmentManager fm) {
       super(fm);
    }

    @Override
    public Fragment getItem(int index) {

        switch (index) {
        case 0:
            // First fragment activity
            return new StatusFragment();
        case 1:
            // Second fragment activity
            return new ScheduleFragment();
         case 2:
             // Third fragment activity
             if (isChapterDetailShowing)
                 return new ChapterDetailFragment();
             else
                 return new BooksFragment();
         }

         return null;
     }

    public void showChapter(int chapter) {
        this.chapter = chapter;
        isChapterDetailShowing = true;
        notifyDataSetChanged();
    }

Then create a method in the Activity, which calls the showChapter() on the adapter. This method would be called in BookFragment's GridView onItemClickListener (use getActivity() and cast it to MainActivity).

Disclaimer: not 100% sure this will work

Upvotes: 2

Related Questions