ViewPager can not remove view in a fragment - android

A fragment named NewsCenterFragment would replace the FramLayout in DrawerActivity.The problem is program will crash when I swipe the viewPager to a next slide. The exception is given which says: java.lang.IllegalStateException: The specified child already has a parent.You must call removeView() on the child's parent first.
public class DrawerActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,Serializable {
private FragmentManager fm;
private NavigationView navigationView;
private NewsMenu data;
private RadioGroup radioGroup;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
radioGroup = (RadioGroup) findViewById(R.id.content_drawer_radioGroup);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
checkCacheForNewsCenterSlideBar();
changeNewsSlideBar();
Fragment homeFragment = new HomeFragment();
fm = getFragmentManager();
fm.beginTransaction().replace(R.id.content_drawer_content,homeFragment).commit();
getSupportActionBar().setTitle("Home page");
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId){
case R.id.content_drawer_radioGroup_shouye:
Fragment homeFragment = new HomeFragment();
fm.beginTransaction().replace(R.id.content_drawer_content,homeFragment).commit();
getSupportActionBar().setTitle("Home page");
break;
case R.id.content_drawer_radioGroup_newscenter:
Fragment newsCenterFragment = new NewsCenterFragment(findNewsTabTitle(),DrawerActivity.this);
fm.beginTransaction().replace(R.id.content_drawer_content,newsCenterFragment).commit();
getSupportActionBar().setTitle("News center");
break;
case R.id.content_drawer_radioGroup_smartservice:
break;
case R.id.content_drawer_radioGroup_goveraffairs:
break;
case R.id.content_drawer_radioGroup_setting:
break;
}
}
});
}
public class NewsCenterFragment extends Fragment {
private ViewPager viewPager;
private Activity mActivity;
private ArrayList<String> title;
private ArrayList<View> views;
public NewsCenterFragment(ArrayList<String> title, Activity activity){
this.title = title;
this.mActivity = activity;
}
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) {
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(mActivity.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.fragment_newscenter_layout,container,false);
viewPager = (ViewPager) view.findViewById(R.id.fragment_newscenter_viewPager);
views = new ArrayList<View>();
View tempLayout = inflater.inflate(R.layout.news_title_layout,container,false);
for(int i=0;i<title.size();i++){
views.add(tempLayout);
}
viewPager.setAdapter(new NewsMenuDetailAdapter());
return view;
}
class NewsMenuDetailAdapter extends PagerAdapter{
#Override
public int getCount() {
return views.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view==(LinearLayout)object;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
String tabTitle = title.get(position);
View view = views.get(position);
TextView textView = (TextView) view.findViewById(R.id.news_title_layout_title);
textView.setText(tabTitle);
container.addView(view);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout)object);
}
}
}
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I have been searching solution for a couple of hours.Please help me out.Thanks a lot.

It's looked like you have N references to one object in your views array from here:
View tempLayout = inflater.inflate(R.layout.news_title_layout,container,false);
for(int i=0;i<title.size();i++){
views.add(tempLayout);
}
So when your adapter started to return items it attached this view (tempLayout) for first time succesfully, but on the second it failed, because tempLayout (i.e. views[i]) already have a parent from previous call instantiateItem.
You should either provide another inflated view or call ((ViewGroup)child.getParent()).removeView(child) before call container.add()

Related

How to show saved data inside multiple fragments?

Intro
Hi guys, currently I am working on a question-form app. In the MainActivity users can add an item after which a QuestionListActivity opens. Clicking on the first item in that list opens the Main2Activity. This activity exists of 3 fragments which all include one question (Edittext). The data implemented by the user in the fragments is saveable. After answering and saving questions, each form appears in the MainActivity as a list. Clicking on these items brings them back to the QuestionListActivity after which clicking on the first item should open the fragments again with their saved data already shown.
Problem
After saving the fragments, the string to the MainActivity is succesfull, eg. the Title as set by saving the first fragment (which asks for the name of the form). Therefore, the saving to my Utilities class was succesfull. The problem is, clicking on a saved item in the MainActivity and then on the first item in the QuestionList to open the Main2Activity (fragments with questions), opens the fragments but with empty EditText fields where the saved data should be shown to view them or make changes.
Question
How is it possible to show the saved data inside multiple fragments instead of in just one activity and what am I doing wrong? And is it recommended to use the same format when using 8 questions (one fragment per question)?
(I couldn't find the right question to use on StackOverFlow, because almost every question about this subject is about the instance state ed. but this isn't a problem in my project)
Codes
Here is my Main2Activity and one fragment(Frag1). The other fragment I have setup the same way as Frag1. I am probably doing something wrong in the fragment java classes but I am unsure what. Hopefully, someone can help me.
public class Main2Activity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private String mNoteFileName;
private Note mLoadedNote;
private EditText title, question2, question3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
title = findViewById(R.id.note_et_title1);
question2 = findViewById(R.id.note_et_question2);
question3 = findViewById(R.id.note_et_question3);
String title;
String question2 ;
String question3;
mNoteFileName = getIntent().getStringExtra("NOTE_FILE");
if(mNoteFileName !=null && !mNoteFileName.isEmpty()) {
mLoadedNote = Utilities.getNoteByName(this, mNoteFileName);
if(mLoadedNote !=null) {
title = mLoadedNote.getTitle();
question2 = mLoadedNote.getQuestion2();
question3 = mLoadedNote.getQuestion3();
}
}
List<Fragment> fragments = new ArrayList<>();
fragments.add(Frag1.newInstance(title));
fragments.add(Frag2.newInstance(question2));
fragments.add(Frag3.newInstance(question3));
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(),fragments);
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_note_new, menu);
return true;
}
private void saveNote() {
Note note;
if(title.getText().toString().trim().isEmpty()){
Toast.makeText(this, "Please enter a title", Toast.LENGTH_SHORT).show();
}
if(mLoadedNote ==null) {
note = new Note(System.currentTimeMillis(), title.getText().toString(), question2.getText().toString(), question3.getText().toString());
}else {
note = new Note(mLoadedNote.getDateTime(), title.getText().toString(), question2.getText().toString(), question3.getText().toString());
}
if (Utilities.saveNote(this, note)){
Toast.makeText(this, "saved", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "not enough space", Toast.LENGTH_SHORT).show();
}
finish();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_note_save:
saveNote();
break;
}
return true;
}
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main2, container, false);
TextView textView = (TextView) rootView.findViewById(R.id.section_label);
textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragments;
public SectionsPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
#Override
public Fragment getItem(final int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
}
}
public class Frag1 extends Fragment {
private static final String EXTRA_TEXT = "text";
private EditText mEtTitle;
public static Frag1 newInstance(String message) {
Bundle args = new Bundle();
args.putString(EXTRA_TEXT, message);
Frag1 fragment = new Frag1();
fragment.setArguments(args);
return fragment;
}
public Frag1 () {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag1_layout, container, false);
mEtTitle = (EditText) view.findViewById(R.id.note_et_title1);
Bundle bundle = getArguments();
if (bundle != null) {
mEtTitle.setText(bundle.getString(EXTRA_TEXT));
}
return view;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_green_light">
<TextView
android:id="#+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="Vraag 1, bv naam" />
<EditText
android:id="#+id/note_et_title1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:ems="10"
android:gravity="top"
android:inputType="textMultiLine" />
I would recommend you to slighlty change your current approach.
First create helper method newInstance in each fragment which will return the instance of that fragment. For example Frag1
public class Frag1 extends Fragment {
private static final String EXTRA_TEXT = "text";
private EditText mEtTitle;
public static Frag1 newInstance(String message) {
Bundle args = new Bundle();
args.putString(EXTRA_TEXT, message);
Frag1 fragment = new Frag1();
fragment.setArguments(args);
return fragment;
}
public Frag1 () {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag1_layout, container, false);
mEtTitle = (EditText) view.findViewById(R.id.note_et_title1);
Bundle bundle = getArguments();
if (bundle != null) {
mEtTitle.setText(bundle.getString(EXTRA_TEXT));
}
return view;
}
}
In SectionsPagerAdapter pass the list of Fragment.
For the reference hereby modified SectionsPagerAdapter.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragments;
public SectionsPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
#Override
public Fragment getItem(final int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
}
Then change the call
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(),<List of Fragments>);
Hereby sharing modified Activity#onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
String title = "";
String question2 = "";
String question3 = "";
mNoteFileName = getIntent().getStringExtra("NOTE_FILE");
if(mNoteFileName !=null && !mNoteFileName.isEmpty()) {
mLoadedNote = Utilities.getNoteByName(this, mNoteFileName);
if(mLoadedNote !=null) {
title = mLoadedNote.getTitle();
question2 = mLoadedNote.getQuestion2();
question3 = mLoadedNote.getQuestion3();
}
}
List<Fragment> fragments = new ArrayList<>();
fragments.add(Frag1.newInstance(title));
fragments.add(Frag2.newInstance(question2));
fragments.add(Frag3.newInstance(question3));
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(),fragments);
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
}
You should use Shared Preferences or Database to save your data and show it.

Android Fragments Overlapping each other

In my App, I have two Fragments: FragmentA and FragmentB which are loaded from my MainActivity by the help of an SlidingMenu.
When FragmentB is shown, it immediatelly starts an AsyncTask in background to load data from a server. The loading process is reflected by an active SwipeRefreshLayout to the user.
When loading is finished, the UI of FragmentB is refreshed with the loaded data, by the help of a delegate which is passed to MyAsyncClass.
I am now facing the following problem:
As soon as processFinish in my delegate is called, I am stopping the Refresh of the SwipeRefreshLayout by the help of swipeRefreshLayout.setRefreshing(false).
If the user is going back to FragmentA while background-Task is still in progress, it appears in about 20% of the cases, that FragmentB is still in background of FragmentA in the User Interface (see Screenshot below).
As you can see in the image, the FragmentA is shown (the text "No tracks played yet" is from FragmentA), but in the background you can see still the FragmentB.
As already mentioned, this is not in 100% of the cases, so it should not be an background/transparency issue. If I comment out the swipeRefreshLayout.setRefreshing(false), then the problem is not reproductible, but somehow I need to stop the SwipeRefreshLayout in case the user stays on FragmentB.
Any idea what causes this behaviour?
AsyncResponse-Interface:
public interface AsyncResponse {
void processFinish(String result);
}
FragmentB-Class:
public class FragmentB extends MyFragment implements SwipeRefreshLayout.OnRefreshListener, AsyncResponse {
private SwipeRefreshLayout swipeRefreshLayout;
private View view;
private RecyclerView recyclerView;
public FragmentB () {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.songs_list, container, false);
swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_layout);
swipeRefreshLayout.setOnRefreshListener(this);
swipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.colorPrimary));
// Set the adapter
Context context = view.getContext();
recyclerView = (RecyclerView) view.findViewById(R.id.listinclude);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider));
List<Song> songsList = databaseHandler.getAllSongs();
setVisibilities(songsList);
this.recyclerViewAdapter = new RecyclerViewAdapter(songsList, mListener, false, false);
recyclerView.setAdapter(this.recyclerViewAdapter);
swipeRefreshLayout.setRefreshing(true);
receive();
return view;
}
private void setVisibilities(List<Song> songsList) {
ViewFlipper viewFlipper = (ViewFlipper) view.findViewById(R.id.viewFlipper);
if (songsList.isEmpty() && viewFlipper.getDisplayedChild() == 0) {
viewFlipper.setDisplayedChild(1);
} else if (!songsList.isEmpty() && viewFlipper.getDisplayedChild() == 1) {
viewFlipper.setDisplayedChild(0);
}
}
#Override
public void onRefresh() {
if (MyOnlineHelper.isOnline(getContext())) {
receive();
} else {
swipeRefreshLayout.setRefreshing(false);
}
}
private void receive() {
new MyAsyncClass(this, getContext()).execute("receiving");
}
#Override
public void processFinish(String output) {
// refreshUI
swipeRefreshLayout.setRefreshing(false);
}
}
FragmentA-Class:
public class FragmentA extends MyFragment implements AsyncResponse {
private View view;
private RecyclerView recyclerView;
public FragmentA() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
List<Song> songsList = myDatabaseHandler.getAllSongs();
view = inflater.inflate(R.layout.home_list, container, false);
// Set the adapter
Context context = view.getContext();
recyclerView = (RecyclerView) view.findViewById(R.id.listinclude);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider));
setVisibilities(songsList);
this.recyclerViewAdapter = new RecyclerViewAdapter(songsList, mListener, false, true);
recyclerView.setAdapter(this.recyclerViewAdapter);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
private void setVisibilities(List<Song> songsList) {
ViewFlipper viewFlipper = (ViewFlipper) view.findViewById(R.id.viewFlipper);
if (songsList.isEmpty() && viewFlipper.getDisplayedChild() == 0) {
viewFlipper.setDisplayedChild(1);
} else if (!songsList.isEmpty() && viewFlipper.getDisplayedChild() == 1) {
viewFlipper.setDisplayedChild(0);
}
}
#Override
public void processFinish(String output) {
// does something
}
}
MyAsyncClass:
public class MyAsyncClass extends AsyncTask<String, Integer, String> {
private AsyncResponse delegate;
private Context mContext;
private MyDatabaseHandler myDatabaseHandler;
public MyAsyncClass(AsyncResponse delegate, Context context) {
this.delegate = delegate;
this.mContext = context;
}
#Override
protected String doInBackground(String... params) {
// calling webservice and writing it to the database
}
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
super.onPostExecute(result);
}
}
MainActivity-Class:
public class MainActivity extends AppCompatActivity implements MyFragment.OnListFragmentInteractionListener, AsyncResponse {
private FragmentA fragmentA = new FragmentA();
private FragmentB fragmentB;
private NavigationView navigationView;
private DrawerLayout drawer;
private Toolbar toolbar;
// index to identify current nav menu item
private static int navItemIndex = 0;
public static String CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
// toolbar titles respected to selected nav menu item
private String[] activityTitles;
// flag to load home fragment when user presses back key
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentA.setDatabaseHandler(this.myDatabaseHandler);
// Init UI
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mHandler = new Handler();
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView = (NavigationView) findViewById(R.id.nav_view);
fabSendButton = (FloatingActionButton) findViewById(R.id.fab);
// Navigation view header
navHeader = navigationView.getHeaderView(0);
// load toolbar titles from string resources
activityTitles = getResources().getStringArray(R.array.sliding_menu_item_activity_titles);
// initializing navigation menu
setUpNavigationView();
if (savedInstanceState == null) {
navItemIndex = 0;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
loadHomeFragment();
}
}
/***
* Returns respected fragment that user
* selected from navigation menu
*/
private void loadHomeFragment() {
// set toolbar title
setToolbarTitle();
// if user select the current navigation menu again, don't do anything
// just close the navigation drawer
if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
drawer.closeDrawers();
return;
}
// Sometimes, when fragment has huge data, screen seems hanging
// when switching between navigation menus
// So using runnable, the fragment is loaded with cross fade effect
// This effect can be seen in GMail app
Runnable mPendingRunnable = new Runnable() {
#Override
public void run() {
// update the activity_main_header_with_item content by replacing fragments
Fragment fragment = getFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
fragmentTransaction.commit();
}
};
// If mPendingRunnable is not null, then add to the message queue
if (mPendingRunnable != null) {
mHandler.post(mPendingRunnable);
}
//Closing drawer on item click
drawer.closeDrawers();
// refresh toolbar menu
invalidateOptionsMenu();
}
private Fragment getFragment() {
switch (navItemIndex) {
case 0:
return this.fragmentA;
case 1:
if (fragmentB == null) {
fragmentB = new FragmentB();
fragmentB.setDatabaseHandler(this.myDatabaseHandler);
}
return fragmentB;
default:
return this.fragmentA;
}
}
private void setToolbarTitle() {
getSupportActionBar().setTitle(activityTitles[navItemIndex]);
}
private void setUpNavigationView() {
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Check to see which item was being clicked and perform appropriate action
switch (menuItem.getItemId()) {
//Replacing the activity_main_header_with_item content with ContentFragment Which is our Inbox View;
case R.id.nav_A:
navItemIndex = 0;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
break;
case R.id.nav_B:
navItemIndex = 1;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_B;
break;
default:
navItemIndex = 0;
}
loadHomeFragment();
return true;
}
});
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.openDrawer, R.string.closeDrawer) {
#Override
public void onDrawerClosed(View drawerView) {
// Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
// Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
super.onDrawerOpened(drawerView);
}
};
//Setting the actionbarToggle to drawer layout
drawer.setDrawerListener(actionBarDrawerToggle);
//calling sync state is necessary or else your hamburger icon wont show up
actionBarDrawerToggle.syncState();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
return true;
}
}
Thanks to Prsnth Gettin High and this post ( When switch fragment with SwipeRefreshLayout during refreshing, fragment freezes but actually still work), wrapping the SwipeRefreshLayout in a FrameLayout helps, like that:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewFlipper
android:id="#+id/viewFlipper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/listinclude"
layout="#layout/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:visibility="visible"/>
<include
android:id="#+id/emptyinclude"
layout="#layout/fragment_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"/>
</ViewFlipper>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
try downcasting the fragment object to the specific fragment.
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment fragment = getFragment();
FragmentA fragA;
FragmentB fragB;
if(fragment intanceof FragmentA)
{
fragA=(FragmentA) fragment;
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
fragmentTransaction.replace(R.id.frame, fragA, FragmentA.TAG);
}
if(fragment instanceof FragmentB)
{
fragB=(FragmentB) fragment;
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
fragmentTransaction.replace(R.id.frame, fragB, FragmentB.TAG);
}
fragmentTransaction.commit();
And may I ask why are you using a runnable to swap fragments?
try reusing the view. It may fix the issue.
`#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(view==null){view = inflater.inflate(R.layout.songs_list, container, false);}`

Where should I implement onClick method in a NavigationDrawer Activity?

I have a navigation drawer and a fragment that generates a list of products. The problem is that when I click on a product it tryes to find onClick method in base activity not in fragment's java class. Should I implement onClick method in the base activity or is there any way to implement it in fragment's class.
This is product's layout "item_order.xml":
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:onClick="orderClick"
android:id="#+id/tOrder"
android:padding="4dp">
....
</RelativeLayout>
Here is the base class:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_waiter);
//set fragment
OrdersFragment fragment=new OrdersFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction=getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container,fragment);
fragmentTransaction.commit();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
OrdersFragment.wa=this;
}
Here is the fragment:
public class OrdersFragment extends Fragment {
private Database db;
private ArrayList<Order> orders=new ArrayList<Order>();
private OrderAdapter adapter;
private ListView listOrders;
public static WaiterActivity wa;
public OrdersFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_orders, container, false);
// Inflate the layout for this fragment
db = new Database();
db.createNewOrderListener(this);
ListView listOrders = (ListView) view.findViewById(R.id.ordersList);
adapter = new OrderAdapter(this.getContext(), R.layout.item_order, orders);
listOrders.setAdapter(adapter);
return view;
}
I think you are talking about list view item selection.
Firstly remove onClick from you xml. Create a function orderClick in you base activity and Then in you fragment add onItemClick listener to your list view.
listOrders.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (getActivity() instanceof "your base activity"){
(("your base activity")getActivity()).orderClick();
}
}
});
You should call activity method for taking action by calling it in your fragment class and pass the itemIndex of item that has been called.
use setOnItemClickListener in your activity, and call the fragments from there only, as:-
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = null;
FragmentManager fragmentManager = getSupportFragmentManager();
switch (position) {
case 0:
fragment = new ProgramFragment();
break;
case 1:
fragment = new FeedbackFragment();
break;
case 2:
fragment = new ShareFragment();
break;
case 3:
fragment = new LogOutFragment();
break;
default:
fragment =null;
}
if (fragment != null) {
fragmentManager.beginTransaction().replace(R.id.main_fragment_container, fragment).commit();
}
mDrawerList.setItemChecked(position, true);
drawerLayout.closeDrawer(mDrawerList);
}
});

NavigationDrawer main page and styling

this is the first application I am creating using a NavigationDrawer. I have a pretty simple question. How do I make the first page in the NavigationDrawer the main one? Also I'm not too familiar with formatting since this is my first time using the drawer so I would appreciate it if someone more familiar could tell me if I am doing it correctly. Right now each page just displays text but eventually it will do more. And one of my questions is how do I make it so that clicking a page in the drawer can open up a new page using a RelativeLayout for example. From my understanding Adapters are only for Views, would I create a completely new activity and call startActivity() in my iteration for the drawerclick? If so, is that efficient? Meaning will it take a long time for the page to load? My main activity is:
public class MainActivity extends Activity {
private String[] mPages;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_layout);
mPages = getResources().getStringArray(R.array.page_titles);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPages));
mTitle = mDrawerTitle = getTitle();
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open,
R.string.drawer_close) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
}
};
// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
/** Swaps fragments in the main content view */
private void selectItem(int position) {
// Create a new fragment and specify the planet to show based on position
Fragment fragment;
if(position == 0){
fragment = new OneFragment();
// Insert the fragment by replacing any existing fragment
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
}
else if(position == 1){
fragment = new TwoFragment();
// Insert the fragment by replacing any existing fragment
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
}
else if(position == 2){
fragment = new ThreeFragment();
// Insert the fragment by replacing any existing fragment
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
}
else if(position == 3){
fragment = new FourFragment();
// Insert the fragment by replacing any existing fragment
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
}
// Highlight the selected item, update the title, and close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPages[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
public static class OneFragment extends Fragment{
public OneFragment(){
}
View rootView;
TextView text;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup contatiner,
Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.drawer_layout,
contatiner, false);
text = (TextView)rootView.findViewById(R.id.text_view1);
text.setText("One");
return rootView;
}
}
public static class TwoFragment extends Fragment{
public TwoFragment(){
}
View rootView;
TextView text;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup contatiner,
Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.drawer_layout,
contatiner, false);
text = (TextView)rootView.findViewById(R.id.text_view1);
text.setText("Two");
return rootView;
}
}
public static class ThreeFragment extends Fragment{
public ThreeFragment(){
}
View rootView;
TextView text;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup contatiner,
Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.drawer_layout,
contatiner, false);
text = (TextView)rootView.findViewById(R.id.text_view1);
text.setText("Three");
return rootView;
}
}
public static class FourFragment extends Fragment{
public FourFragment(){
}
View rootView;
TextView text;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup contatiner,
Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.drawer_layout,
contatiner, false);
text = (TextView)rootView.findViewById(R.id.text_view1);
text.setText("Four");
return rootView;
}
}
}
I apologize for the lengthy question, but the developer site wasn't helping out too much and I want to make sure I do this correctly the first time so I don't have to go back too much
Whatever you want to show needs to be within the child of the DrawerLayout. In your case, I think you would do a fragment transaction in onCreate() to put whatever fragment you want visible first inside of the content area.
if (savedInstanceState == null) {
fragment = new OneFragment();
// Insert the fragment by replacing any existing fragment
getFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment).commit();
}
You can hold references to these fragments so you don't create a new instance of them each time the user makes a selection. You probably also want to make sure the new selection isn't the same as the current one, or else you will have extra transactions you don't need.
For opening a "new page", you want to use startActivity() and show another activity with it's own layout. Generally speaking, don't be concerned about how long it takes an Activity to load unless you are specifically doing some meaningful work (like loading a bunch of data out of a database).
Lastly, Adapters are specifically for AdapterViews (like ListView) and are an entirely different matter. They are used in conjunction with specific UI components to generate child views for representing potentially large data sets and which can be recycled for efficiency reasons. I suggest you watch The World of ListView if you want more information/clarity about that.

onClick inside fragment giving me NPE

I've been wrestling with this for quite a while now.
I switched from having a regular Activity to now using fragments (by users recommendations), but I've been getting the same issue.
I have 3 pages that are now 3 fragments inside of a ViewPager. I want the button with the id addSiteButton in the addSite fragment; when clicked, to scroll over to setCurrentItem(2).
Any help is appreciated! Here's my code.
The FragmentActivity
public class fieldsActivity extends FragmentActivity {
private static final int NUMBER_OF_PAGES = 3;
ViewPager mPager;
MyFragmentPagerAdapter mMyFragmentPagerAdapter;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// to create a custom title bar for activity window
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.fields);
// use custom layout title bar
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.topbar);
mPager = (ViewPager) findViewById(R.id.fieldspager);
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mMyFragmentPagerAdapter);
mPager.setCurrentItem(1);
}
private static class MyFragmentPagerAdapter extends FragmentPagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int page) {
switch (page) {
case 0: return new settingFields();
case 1: return new addSite();
case 2: return new createSite();
}
return null;
}
#Override
public int getCount() {
return NUMBER_OF_PAGES;
}
}
The class with the button
public class addSite extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (container == null) {
return null;
}
RelativeLayout mRelativeLayout = (RelativeLayout) inflater.inflate(R.layout.add_site, container, false);
final ViewPager mPager = (ViewPager) mRelativeLayout.findViewById(R.id.fieldspager);
Button addSiteButton = (Button) mRelativeLayout.findViewById(R.id.addSiteButton);
addSiteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mPager.setCurrentItem(2, true);
}
});
return mRelativeLayout;
}
}
I feel like I'm going in circles and not getting the desired motion.
Thanks for the help!
Simply make the Fragment as a class inside the FragmentActivity and take out the variable shadowing in onCreateView() since your pager is a global variable.
public class fieldsActivity extends FragmentActivity {
private static final int NUMBER_OF_PAGES = 3;
ViewPager mPager;
MyFragmentPagerAdapter mMyFragmentPagerAdapter;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// to create a custom title bar for activity window
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.fields);
// use custom layout title bar
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.topbar);
mPager = (ViewPager) findViewById(R.id.fieldspager);
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mMyFragmentPagerAdapter);
mPager.setCurrentItem(1);
}
public static class addSite extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RelativeLayout mRelativeLayout = (RelativeLayout) inflater.inflate(R.layout.add_site, container, false);
//final ViewPager mPager = (ViewPager) mRelativeLayout.findViewById(R.id.fieldspager);
Button addSiteButton = (Button) mRelativeLayout.findViewById(R.id.addSiteButton);
addSiteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mPager.setCurrentItem(2, true);
}
});
return mRelativeLayout;
}
}
}
Also consider using the #Override annotation whenever you override a method so you don't make mistakes and use proper naming conventions. Java classes start with a capital.

Categories

Resources