Reputation: 51
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
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