4

I've been stuck on this all day, and I can't seem to find an answer here that fits my situation close enough for me to put to use.

Here's a look at my UI, the tabs and listviews function nicely: https://i.stack.imgur.com/84kRY.png

When I click a list item, like Blue, in portrait I want it to display a new fragment being a blue screen, and in landscape it displays that fragment on half the screen, and the listview in the other. I'm using ActionBarSherlock and fragments to accomplish this.

I built it from the inside out, so I started with a single list and it worked as I wanted it to. Then I added the tabs, the pager functionality, and the other list. Somewhere in that process the fragment displaying stopped working, and everytime I click anything I get a crash.

Here's the clicky part of one of my ListView activities

public class TitlesFragment extends SherlockListFragment{

boolean mDualPane;
int mCurCheckPosition = 0;

    .
    .
    .

@Override
public void onSaveInstanceState(Bundle outState){
    super.onSaveInstanceState(outState);
    outState.putInt("curChoice", mCurCheckPosition);
}

@Override
public void onListItemClick(ListView l, View v, int position, long id){
    showDetails(position);
}

void showDetails(int position){
    SherlockFragment newContent = new SherlockFragment();
    FragmentManager fm = getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    
    
    if(mDualPane){
        switch(position){
        case 0:
            newContent = new Blue();
            break;
        case 1:
            newContent = new Red();
            break;
        case 2:
            newContent = new Green();
            break;
        case 3:
            newContent = new Yellow();
            break;
        case 4:
            newContent = new Purple();
            break;
            
    
    } ft.replace(R.id.details, newContent);
    } else {
        switch(position){
        case 0:
            newContent = new Blue();
            break;
        case 1:
            newContent = new Red();
            break;
        case 2:
            newContent = new Green();
            break;
        case 3:
            newContent = new Yellow();
            break;
        case 4:
            newContent = new Purple();
            break;
        
        
    }ft.replace(R.id.titles, newContent);
    }
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.addToBackStack(null);
    ft.commit();
    return;
}
}

Here's the Blue class

public class Blue extends SherlockFragment{

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
}

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
    return inflater.inflate(R.layout.blue, container, false);
}

}

The Blue layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/blue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000FF"
android:orientation="vertical" >

</LinearLayout>

The layout I want it to replace in landscape

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal"
android:id="@+id/fragment_layout_support_land" >

<fragment
    android:id="@+id/titles_land"
    android:layout_width="0px"
    android:layout_height="match_parent"
    android:layout_weight="1"
    class="***.TitlesFragment" />

<fragment
    android:id="@+id/details"
    android:layout_width="0px"
    android:layout_height="match_parent"
    android:layout_weight="2" />

</LinearLayout>

And the layout to replace in portrait

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_layout_support"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<fragment
    android:id="@+id/titles"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="***.TitlesFragment" />

</FrameLayout>

And last my LogCat

LogCat Screenshot Here

I used a tutorial to get to fragments working before. I can't post more links but you'll find it on youtube called ListFragment Tutorial Part 2.

At this point I'm open to anything, including starting from scratch and doing the code differently, but I'd love even more to understand what is happening here and why, so I can learn from it. Thanks!

EDIT Tried something new and got a new error

@Override
public void onListItemClick(ListView l, View v, int position, long id){
    showDetails(position);
}

void showDetails(int position){
    SherlockFragment newContent = new SherlockFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.add(R.id.fragment_layout_support, newContent);
    transaction.commit();
    
    
    if(mDualPane){
        switch(position){
        case 0:
            newContent = new Blue();
            break;
        case 1:
            newContent = new Red();
            break;
        case 2:
            newContent = new Green();
            break;
        case 3:
            newContent = new Yellow();
            break;
        case 4:
            newContent = new Purple();
            break;
            
    
    } transaction.add(R.id.fragment_layout_support_land, newContent);
    } else {
        switch(position){
        case 0:
            newContent = new Blue();
            break;
        case 1:
            newContent = new Red();
            break;
        case 2:
            newContent = new Green();
            break;
        case 3:
            newContent = new Yellow();
            break;
        case 4:
            newContent = new Purple();
            break;
        
        
    }transaction.replace(R.id.fragment_layout_support, newContent);
    }
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    transaction.addToBackStack(null);
    transaction.commit();
    return;
}
}

New LogCat

    FATAL EXCEPTION: main java.lang.IllegalStateException: commit already called
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:582)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at [package].TitlesFragment.showDetails(TitlesFragment.java:97)
at [package].TitlesFragment.onListItemClick(TitlesFragment.java:44)
at android.support.v4.app.ListFragment$2.onItemClick(ListFragment.java:58)
at android.widget.AdapterView.performItemClick(AdapterView.java:298)
at android.widget.AbsListView.performItemClick(AbsListView.java:1100)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:2788)
at android.widget.AbsListView$1.run(AbsListView.java:3463)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Syscall
  • 19,327
  • 10
  • 37
  • 52
RyWalk
  • 43
  • 1
  • 1
  • 7
  • Have a look at [this answer](http://stackoverflow.com/a/7717750/1465828), your `fragment` handling has some problems maybe.. – Aprian Sep 16 '13 at 01:59
  • I've tried using the xml from that solution before, but wasn't sure how to go about changing my java to fit it. I can try playing around with that more. Thanks for the reply. – RyWalk Sep 16 '13 at 02:27
  • Put the java code in the `OnCreate` method of your activity. – Aprian Sep 16 '13 at 02:31
  • Would it go similarly in OnActivityCreated? Sorry if that's a dumb question. I'm just not sure if I should put it there, or replace the stuff I have after my OnListItemClick. – RyWalk Sep 16 '13 at 02:36
  • I don't think it is the same. You have a class that **extends** `Activity` or `SherlockActivity` or `***Activity`, do you? No, it has nothing to do with your `TitlesFragment`. – Aprian Sep 16 '13 at 02:50
  • No, it's all fragments. The MainActivity is a SherlockFragmentActivity, the two lists are SherlockListFragments, and each color activity is a SherlockFragment. I tried applying that other answer in my ListFragment and got a new error "commit already called" I'll post what I did in an edit. – RyWalk Sep 16 '13 at 03:14
  • The error is self-explanatory. You created a fragment transaction, committed the changes, and reuse the transaction and commit again. Try create a new transcation for the if/else part. – Lawrence Choy Sep 16 '13 at 03:48

1 Answers1

7

You should change your portrait xml to:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_layout_support"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/titles"
        android:layout_width="0px"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</FrameLayout>

And in your MainActivity's onCreate method, put:

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    TitlesFragment title = new TitlesFragment();
    getSupportFragmentManager().beginTransaction().replace(R.id.titles, title).commit();
}

Also please change back the code in TitlesFragment OR see my showDetails below.

Note : For Landscape, I hope you can figure it out yourself. Your current way of handling land-portrait, IMO is not the best way to do it. Read Layout Aliases for more details.

Extra : You don't have to create Blue, Green, Red, Yellow classes. You can create a Rainbow class.

public class Rainbow extends SherlockFragment {

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
    }

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

        // default color
        int color = Color.WHITE;

        // get the color if provided through setArguments(Bundle args)
        if (getArguments() != null) {
            color = getArguments().getInt("color");
        }

        view.findViewById(R.id.rainbow).setBackgroundColor(color);

        return view;
    }
}

Change your showDetails to:

 void showDetails(int position) {
    FragmentManager fm = getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();

    int color;
    switch (position) {
    case 0:
        color = Color.BLUE;
        break;
    case 1:
        color = Color.RED;
        break;
    default:
        color = Color.WHITE;
    }

    Rainbow rainbow = new Rainbow();
    Bundle arguments = new Bundle();
    arguments.putInt("color", color);
    rainbow.setArguments(arguments);

    ft.replace(R.id.titles, rainbow);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.addToBackStack(null);
    ft.commit();
    return;
}
Syscall
  • 19,327
  • 10
  • 37
  • 52
Aprian
  • 1,718
  • 1
  • 14
  • 24
  • Awesome! I did what you said, and I no longer have a crash on list item clicks! A new error has shown up though, unrelated. The fragment opens up not over the listfragment. So clicking blue makes a blue background behind the list, not a blue screen over it. It also crashes when switching to landscape. You did solve my original dilemma though, so thank you! – RyWalk Sep 16 '13 at 04:13
  • That's weird. Your list should have been replaced by `Rainbow` and shouldn't be shown anymore. Check your resource id please. – Aprian Sep 16 '13 at 04:18
  • Hmmmm.. You are using `add` right? You should use `replace(R.id.titles, rainbow);` – Aprian Sep 16 '13 at 04:20
  • Thanks for the extra info too, I'll look into these new problems a bit to try to figure them out. As for the rainbow class, I had something like that in mind. I was working my way there but I had to get over this roadblock first. On my other list I was going to open specific textviews, so I was going to have an xml for each, but try putting each class as static classes in a single class. – RyWalk Sep 16 '13 at 04:20