0

I am making an app using this tutorial. I made some changes in my code, ie I wanted to get data from server to my main activity and pass it to my fragments. Before that , when I would open the app it worked perfectly, bu now it crashes. I have tried a bunch of answers from stackoverflow (1, 2, 3, 4, 5...) before asking a question, but none of them answered my question. When I was getting restaurants from fragment directly it worked perfectly but passing the data from the activity causes this error.

Main Activity (I pass get data from server and pass it to fragment):

TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.tab_map)));
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.tab_list)));
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.tab_my_list)));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);

final ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
final PagerAdapter adapter = new PagerAdapter
    (getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

RestaurantsFragment restaurantsFragment = new RestaurantsFragment();
Bundle args = new Bundle();
args.putParcelableArrayList("restaurantList", (ArrayList<? extends Parcelable>) restaurantList);
restaurantsFragment.setArguments(args);

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.sliding_tabs, restaurantsFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

Restaurant Fragment (I do get data from my main activity, I get the restaurants from the server when I debug):

public class RestaurantsFragment extends Fragment {

private static final String TAG = RestaurantsFragment.class.getSimpleName();

// Restaurants json url
private ProgressDialog pDialog;
private ArrayList restaurantList = new ArrayList<>();
private ListView listView;
private CustomListAdapter adapter;

@Override
public View onCreateView(LayoutInflater inflater,
                         ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_restaurants, container, false);

    Bundle bundle = this.getArguments();
    if (bundle != null) {
        restaurantList = bundle.getParcelableArrayList ("restaurantList");
    }

    listView = (ListView) view.findViewById(R.id.restaurants_list);
    adapter = new CustomListAdapter(getActivity(), restaurantList);
    listView.setAdapter(adapter);

    pDialog = new ProgressDialog(getActivity());

    pDialog.setMessage("Loading...");
    pDialog.show();


    return view;
}

fragment_restaurants

<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"
tools:context=".sliderfragments.RestaurantsFragment">

<ListView
    android:id="@+id/restaurants_list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:divider="@color/list_divider"
    android:dividerHeight="1dp"
    android:listSelector="@drawable/list_row_selector" />

</RelativeLayout>

list_row

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_row_selector"
android:padding="8dp">

<!-- Thumbnail Image -->
<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/thumbnail"
    android:background="@drawable/default_profile"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:layout_alignParentLeft="true"
    android:layout_marginRight="8dp" />

<!-- User Name -->
<TextView
    android:id="@+id/userName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/thumbnail"
    android:layout_toRightOf="@+id/thumbnail"
    android:textSize="@dimen/userName"
    android:textStyle="bold" />

<!-- Date -->
<TextView
    android:id="@+id/date"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/userName"
    android:layout_marginTop="1dip"
    android:layout_toRightOf="@+id/thumbnail"
    android:textSize="@dimen/date" />

<!-- Time -->
<TextView
    android:id="@+id/time"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/date"
    android:layout_marginTop="5dp"
    android:layout_toRightOf="@+id/thumbnail"
    android:textColor="@color/time"
    android:textSize="@dimen/time" />

</RelativeLayout>

content_main

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/app_bar_main">

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

    <android.support.design.widget.TabLayout
        android:id="@+id/sliding_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />
</android.support.design.widget.AppBarLayout>

Pager Adapter:

public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;

public PagerAdapter(FragmentManager fm, int NumOfTabs) {
    super(fm);
    this.mNumOfTabs = NumOfTabs;
}

@Override
public Fragment getItem(int position) {

    switch (position) {
        case 0:
            MapsFragment tab1 = new MapsFragment();
            return tab1;
        case 1:
            RestaurantsFragment tab2 = new RestaurantsFragment();
            return tab2;
        case 2:
            MyRestaurantsFragment tab3 = new MyRestaurantsFragment();
            return tab3;
        default:
            return null;
    }
}

@Override
public int getCount() {
    return mNumOfTabs;
}
}

Stack trace:

10-09 12:30:12.755 32374-32374/? E/AndroidRuntime: FATAL EXCEPTION: main
  Process: com.test.kemo.restaurant, PID: 32374
  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.test.kemo.restaurant/com.test.kemo.restaurant.MainActivity}: java.lang.IllegalStateException: HorizontalScrollView can host only one direct child
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
  at android.app.ActivityThread.access$800(ActivityThread.java:135)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:136)
  at android.app.ActivityThread.main(ActivityThread.java:5021)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:827)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:643)
  at dalvik.system.NativeStart.main(Native Method)
  Caused by: java.lang.IllegalStateException: HorizontalScrollView can host only one direct child
  at android.widget.HorizontalScrollView.addView(HorizontalScrollView.java:216)
  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1083)
  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
  at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:330)
  at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
  at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1174)
  at android.app.Activity.performStart(Activity.java:5347)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2168)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
  at android.app.ActivityThread.access$800(ActivityThread.java:135) 
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
  at android.os.Handler.dispatchMessage(Handler.java:102) 
  at android.os.Looper.loop(Looper.java:136) 
  at android.app.ActivityThread.main(ActivityThread.java:5021) 
  at java.lang.reflect.Method.invokeNative(Native Method) 
  at java.lang.reflect.Method.invoke(Method.java:515) 
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:827) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:643) 
  at dalvik.system.NativeStart.main(Native Method) 
Community
  • 1
  • 1
Banana
  • 2,435
  • 7
  • 34
  • 60
  • you have got a scrollView in your MainActivity right ? you cant add two children to one scrollView !! the problem is not what you think its about scrollview and the children inside it which cant be more than 1 !! – Amir Ziarati Oct 09 '16 at 11:22
  • @Amir Ziarati This worked without a problem when I got the list from server in my fragment. But when I changed it and made the server call in my main activity, and then passed it to my fragment this happened. – Banana Oct 09 '16 at 11:25
  • put the xml code of your mainActivity in your Question – Amir Ziarati Oct 09 '16 at 11:29
  • @AmirZiarati I added my content_main above the stack trace – Banana Oct 09 '16 at 11:33
  • Where u are using HorizontalScrollView? – Alex Chengalan Oct 09 '16 at 11:37
  • Rebuild the project and run it again – Alex Chengalan Oct 09 '16 at 11:40
  • @AlexChengalan Cleaned and rebuilt it a few times, but still nothing – Banana Oct 09 '16 at 11:41
  • 1
    `HorizontalScrollView` is used internally by `TabLayout`. Two options: **1)** Remove `addView` calls and listener and call `setupWithViewPager` instead. Your `PagerAdapter` should implement `getPageTitle` and `getCount`. **2)** That's it, don't reinvent the wheel. **Remember:** Your view pager adapter populates the tab layout. Not the other way around. Tab layout is part of presentation layer which reflects your data set represented by the pager adapter. – Eugen Pechanec Oct 09 '16 at 12:36

1 Answers1

1

you are adding your fragment to your sliding tab view. you wrote :

fragmentTransaction.replace(R.id.sliding_tabs, restaurantsFragment);

tab layout is a child of horizontal scrollview see documentation: https://developer.android.com/reference/android/support/design/widget/TabLayout.html

i dont know how your application works but you cant add your fragment to TabLayout here cause it makes multiple children for that that is now allowed (TabLaout is actually a horizontal scrollView inside)

in fragmentTransaction.replace() method that i mentioned you must specify the container in which you want to add the fragment. from what your code says you are using the tabLayput for title of your viewpager not for replacing your fragment in it.

make a place (container) in your main activity in which you want to add your fragment in. absolutely its not in your R.id.sliding_tabs, beside your titles of viewpager.

Amir Ziarati
  • 14,248
  • 11
  • 47
  • 52
  • I am a beginner so I am a little bit confused. This code worked before, I used the tutorial step by step and there was never any issue before. – Banana Oct 09 '16 at 11:53
  • where do you want the fragment in ? in view pager ? below view pager ? where ? – Amir Ziarati Oct 09 '16 at 12:01
  • 1
    look i think you need the fragment inside the viewpager if so you need to move the adding fragment code completely to adapter in getItem() method of adapter. then send whatever you got from the server to adapter in some way and then in your getItem() method of adapter create the fragment using that data. and return the fragment. – Amir Ziarati Oct 09 '16 at 12:06
  • look at this link for full instruction of view pager with fragments: http://stackoverflow.com/questions/18413309/how-to-implement-a-viewpager-with-different-fragments-layouts – Amir Ziarati Oct 09 '16 at 12:08
  • 1
    ok you dont need to add your fragment in your mainactivity just send the data to the adapter somehow and then there you can set the data to the desired fragment before creating that fragment. – Amir Ziarati Oct 09 '16 at 12:27
  • So, basically what I need to do is get the data from the server in my MainActivity, and pass that data to my PagerAdapter? One more question how would I set the data to a certain fragment in PagerAdapter? – Banana Oct 09 '16 at 12:32
  • 1
    the easiest way is to get the data in fragment constructor or writing a method like setData(Data theData) in the fragment and call that after instantiating and ready to go. – Amir Ziarati Oct 09 '16 at 12:34
  • Tiarati Thank you for your help Amir, I will start working on fixing this :) – Banana Oct 09 '16 at 12:36
  • 1
    your welcome ;) comment if you need any help again ;) – Amir Ziarati Oct 09 '16 at 12:42
  • Just one more question, the reason I wanted to get the list from the server in my main activity is to be able to get it when the app starts, and pass it to both restaurantListFragment and mapFragment, I do not want to have to make multiple calls once the app has started. Can I do the same if I put this server call inside the adapter? Would it update when the app starts. – Banana Oct 09 '16 at 13:35
  • 1
    Dont put your api call in the adapter its bit a good practice . The best in ur case is calling in activity ;) – Amir Ziarati Oct 09 '16 at 14:11