2

I'm trying out the new class in android Honeycomb preview, and I've got a small issue. I am making a baseball scoring app, and I want the buttons on the left (Action Menu) to switch the "Action Pane" on the right, which I've set up as a fragment.

I'd like the buttons' onClickListener() to call a Fragment Transaction to swap it out. So far it works, EXCEPT that when the app loads, it creates the default fragment, but when I hit a button, instead of REPLACING the default fragment, it creates a whole new one next to it.

I've looked for hours, and I can't see what I'm doing wrong...

Keep in mind I'm new to java/android/programming, so I might be missing something that's painfully obvious.

hc_test.java (main activity)

package com.pte.hc_test;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class hc_test extends Activity {
    /** Called when the activity is first created. */

    /* declare class-level variables */
//  private LinearLayout touchPad;
//  private TextView touchCoordText;

    private Button pitchButton;
    private Button hitButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        pitchButton = (Button)findViewById(R.id.actionButton1);
        hitButton = (Button)findViewById(R.id.actionButton2);

        pitchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                swapFragment(actionType.PITCH_ACTION);
            }
        });

        hitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                swapFragment(actionType.HIT_ACTION);
            }
        });
    }

    private void swapFragment(int myType){

        Fragment f = new actionFragment(myType);

        // Execute a transaction, replacing any existing
        // fragment with this one inside the frame.
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.actionFragment, f);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.addToBackStack(null);
        ft.commit();

    }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>

<!-- this is the parent layout of the whole screen -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#2F2F4F"
    >

    <!-- SCOREBOARD MASTER LAYOUT -->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >

        <!-- team name placeholders -->
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:padding="5dp"
            >
            <TextView style="@style/inningLabel"
                android:text="TEAM"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <TextView style="@style/inningValue"
                android:text="@string/visitor"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <TextView style="@style/inningValue"
                android:text="@string/home"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
        </LinearLayout>
        <!-- end team names -->

        <!-- Inning table -->
        <HorizontalScrollView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:fadingEdge="vertical">

            <TableLayout
                android:id = "@+id/innings"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp"
                >
                <!-- inning label row -->

                <!-- get these done with code?? -->
                <TableRow android:layout_height="wrap_content">
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn1_label"
                        android:text="1"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn2_label"
                        android:text="2"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn3_label"
                        android:text="3"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn4_label"
                        android:text="4"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn5_label"
                        android:text="5"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn6_label"
                        android:text="6"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn7_label"
                        android:text="7"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn8_label"
                        android:text="8"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningLabel"
                        android:id="@+id/inn9_label"
                        android:text="9"
                        android:layout_height="wrap_content"
                        />
                </TableRow>
                <!-- end inning labels -->

                <!-- top inning row -->
                <TableRow android:layout_height="wrap_content">
                    <TextView style="@style/inningValue"
                        android:id="@+id/top1_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top2_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top3_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top4_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top5_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top6_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top7_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top8_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/top9_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                </TableRow>
                <!-- end top inning row -->

                <!-- bottom inning row -->
                <TableRow android:layout_height="wrap_content">
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot1_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot2_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot3_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot4_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot5_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot6_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot7_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot8_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                    <TextView style="@style/inningValue"
                        android:id="@+id/bot9_label"
                        android:text="0"
                        android:layout_height="wrap_content"
                        />
                </TableRow>
                <!-- end bottom inning row -->

            </TableLayout>
        </HorizontalScrollView>
        <!-- end inning table -->

        <!-- Runs, Hits, Errors Count -->
        <TableLayout
            android:id = "@+id/RHE"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:padding="5dp">

            <TableRow android:layout_height="wrap_content">
                <TextView style="@style/inningLabel"
                    android:id="@+id/runLabel"
                    android:text="R"
                    android:layout_height="wrap_content"
                    />
                <TextView style="@style/inningLabel"
                    android:id="@+id/hitLabel"
                    android:text="H"
                    android:layout_height="wrap_content"
                    />
                <TextView style="@style/inningLabel"
                    android:id="@+id/errorLabel"
                    android:text="E"
                    android:layout_height="wrap_content"
                    />
            </TableRow>

            <TableRow android:layout_height="wrap_content">
                <TextView style="@style/inningValue"
                    android:id="@+id/visitorRuns"
                    android:text="0"
                    android:layout_height="wrap_content"
                    />
                <TextView style="@style/inningValue"
                    android:id="@+id/visitorHits"
                    android:text="0"
                    android:layout_height="wrap_content"
                    />
                <TextView style="@style/inningValue"
                    android:id="@+id/visitorErrors"
                    android:text="0"
                    android:layout_height="wrap_content"
                    />
            </TableRow>

            <TableRow android:layout_height="wrap_content">
                <TextView style="@style/inningValue"
                    android:id="@+id/homeRuns"
                    android:text="0"
                    android:layout_height="wrap_content"
                    />
                <TextView style="@style/inningValue"
                    android:id="@+id/homeHits"
                    android:text="0"
                    android:layout_height="wrap_content"
                    />
                <TextView style="@style/inningValue"
                    android:id="@+id/homeErrors"
                    android:text="0"
                    android:layout_height="wrap_content"
                    />
            </TableRow>

        </TableLayout>

    </LinearLayout>
    <!-- END OF SCOREBOARD LAYOUT -->

    <!-- MAIN ACTIVITY SECTION -->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <!-- ACTION MENU BEGIN -->
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">

            <Button
                android:id="@+id/actionButton1"
                android:text="ActionButton1"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                />
            <Button
                android:id="@+id/actionButton2"
                android:text="ActionButton2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                />
            <Button
                android:id="@+id/actionButton3"
                android:text="ActionButton3"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                />
            <Button
                android:id="@+id/actionButton4"
                android:text="ActionButton4"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                />
            <Button
                android:id="@+id/actionButton5"
                android:text="ActionButton5"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                />

        </LinearLayout>
        <!-- ACTION MENU END -->

        <!-- ACTION FRAME BEGIN -->

        <fragment class="com.pte.hc_test.actionFragment"
            android:id="@+id/actionFragment"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <!-- ACTION FRAME END -->

    </LinearLayout>
    <!-- MAIN ACTIVITY SECTION END -->

    <!-- LIVE STATS FRAME BEGIN -->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <!-- left live stat pane -->
        <LinearLayout
            android:id="@+id/left_stat_pane"
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            >

            <TextView style="@style/statHeader"
                android:id="@+id/left_playerName"
                android:text="{PITCHER NAME}"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />

            <TextView style="@style/statText"
                android:id="@+id/left_stat1"
                android:text="Stat1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <TextView style="@style/statText"
                android:id="@+id/left_stat2"
                android:text="Stat2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <TextView style="@style/statText"
                android:id="@+id/left_stat3"
                android:text="Stat3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
        </LinearLayout>
        <!-- end left live stat pane -->

        <!-- right live stat pane -->
        <LinearLayout
            android:id="@+id/right_stat_pane"
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            >

            <TextView style="@style/statHeader"
                android:id="@+id/right_playerName"
                android:text="{BATTER NAME}"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />

            <TextView style="@style/statText"
                android:id="@+id/right_stat1"
                android:text="Stat1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <TextView style="@style/statText"
                android:id="@+id/right_stat2"
                android:text="Stat2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <TextView style="@style/statText"
                android:id="@+id/right_stat3"
                android:text="Stat3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />

        </LinearLayout>
        <!-- end right live stat pane -->

    </LinearLayout>

</LinearLayout>

actionFragment.java

package com.pte.hc_test;

import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class actionFragment extends Fragment {

    // class variables
    int mActivityType;

    // default (null) constructor
    public actionFragment(){
        Log.v("PTE", "null constructor");       
    }

    public actionFragment(int n){
        mActivityType = n;
        Log.v("PTE", "explicit constructor (" + n + ")");
    }

    @Override
    public void onCreate(Bundle saved){
        super.onCreate(saved);
        if (saved != null){
            mActivityType = saved.getInt("Type");
        }
        Log.v("PTE", "FIRE: actionFragment.onCreate()");
    }

    @Override
    public void onSaveInstanceState(Bundle toSave){
        toSave.putInt("Type", mActivityType);
        Log.v("PTE", "FIRE: actionFragment.onSaveInstanceState()");
    }

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

        Log.v("PTE", "FIRE: actionFragment.onCreateView()");
        Log.v("PTE", "with mActivityType == " + mActivityType);
        try {
            Log.v("PTE", "with onCreateView()'s container = " + container.toString());
        } catch (Exception e) {
            Log.v("PTE", "could not convert container to string. Must be null");
            Log.v("PTE", e.toString());
        }

        Context c = getActivity().getApplicationContext();
        LinearLayout actionPane = new LinearLayout(c);

        switch (mActivityType) {
            case actionType.PITCH_ACTION:
                Log.v("PTE", "FIRE: actionFragment.pitchPane()");

                // instantiate all the required views
                 // parent container
                TextView topLabel = new TextView(c);
                TableLayout strikeZone = new TableLayout(c);
                ImageView image = new ImageView(c);

                // set properties for each view
                actionPane.setOrientation(LinearLayout.VERTICAL);

                topLabel.setText("top Label Text");

                // create the strike zone table
                for(int i=1; i<6; i++){
                    TableRow tr = new TableRow(c);

                    for(int j=1; j<6; j++){
                        TextView tv = new TextView(c);
                        tv.setText("C" + j + ":R" + i);
                        tv.setPadding(3, 3, 3, 3);
                        tr.addView(tv);
                    } 
                    strikeZone.addView(tr);
                }

                image.setPadding(0, 60, 0, 30);
                image.setImageResource(R.drawable.homeplate);

                // add child views to parent
                actionPane.addView(topLabel);
                actionPane.addView(strikeZone);
                actionPane.addView(image);

                return actionPane;

            case actionType.HIT_ACTION:
                Log.v("PTE", "FIRE: actionFragment.hitPane()");

                // simple layout with a text view for testing
                TextView placeholder = new TextView(c);
                placeholder.setText("This is a placeholder");

                actionPane.addView(placeholder);
                return actionPane;

            default:
                Log.v("PTE", "FIRE: actionFragment.defaultPane()");                 

                            // If I comment this TextView out, I achieve my intended behavior
                TextView label = new TextView(c);
                label.setText("This is the default pane");
                actionPane.addView(label);

                return actionPane;
        }
    }

}
Programmer Bruce
  • 64,977
  • 7
  • 99
  • 97
Peter
  • 808
  • 2
  • 11
  • 17
  • I don't know exactly why, but I've managed to fix the issue. If I remove the child view from the default fragment (the TextView placeholder I was using), it works as intended. – Peter Feb 20 '11 at 22:05
  • Should I start a new question about why this behavior is happening? Otherwise, I'd still love for someone to explain why this happens, either on this thread or another. – Peter Feb 20 '11 at 22:07

2 Answers2

2

The placeholder text you were putting in the default for the switch statement was creating a view via your LinearLayout actionPane. A fragment was never added to the container. When you hit your buttons, the swapFragment method was called and a fragment added to the container next to the actionPane view.

If you delete the creation of the actionPane in the default you didn't see the issue as you noted. If you wanted to display some default view or text in a fragment for the initial launch of the app to be replaced by the fragments fired by the buttons, you can add a fragment to the container in the hc_test onCreate method. This will then be swapped out when you fire the buttons. I tested this and it works, may not be the best way and its 2 am now so please excuse me if I'm not writing clearly! Can send you or post the code if you like.

I'm curious if you found a tutorial to help you set up your fragments with the buttons? All I could find were listFragment examples and was struggling until I found your post.

Thanks,

chucky
  • 110
  • 5
  • Thanks, Chucky. I have it working too, when I get home tonight I'll post the working version of the code as well as some links I found helpful in dealing with fragments. – Peter Mar 03 '11 at 12:26
2

I've made a few changes to the code, and it works as I intended. For anyone who's interested, here's the relevant snippits from the working version. I didn't post the code for the individual fragment layouts, but it's really just the xml version of what I was doing in the code in the first draft. I'm liking the simplicity of the inflater object that onCreateView utilizes, it keeps the code to a minimum, and I can make the layout changes in XML without changing code.

actionFragment.java

package com.pte.StatCast;

// imports


public class actionFragment extends Fragment {

    // class variables
    int mActivityType;

    // default (null) constructor
    public actionFragment(){

    }

    public actionFragment(int n){
        this.mActivityType = n;
    }

    @Override
    public void onCreate(Bundle saved){
        super.onCreate(saved);
        if (saved != null){
            mActivityType = saved.getInt("Type");
        }
    }

    @Override
    public void onSaveInstanceState(Bundle toSave){
        toSave.putInt("Type", mActivityType);
    }

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

        Context c = getActivity().getApplicationContext();
        LinearLayout.LayoutParams p = 
            new LinearLayout.LayoutParams(
                    LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1);
        View actionPane = new View(c);

        switch (mActivityType) {
            case actionType.PITCH_ACTION:

                // inflate XML resource to create pitch_frag view
                actionPane = inflater.inflate(R.layout.pitch_frag, null);
                actionPane.setLayoutParams(p);

                // set up listener for touch events
                ImageView strikeZoneImg = (ImageView)actionPane.findViewById(R.id.strikeZone);
                strikeZoneImg.setOnTouchListener(new OnTouchListener(){

                    @Override
                    public boolean onTouch(View v, MotionEvent e) {

                        //DO STUFF
                });

                return actionPane;

            case actionType.HIT_ACTION:

                // inflate XML resource to create hit_frag view
                actionPane = inflater.inflate(R.layout.hit_frag, null);
                actionPane.setLayoutParams(p);
                return actionPane;

            default:
                LinearLayout l = new LinearLayout(c);
                l.setLayoutParams(p);

                return l; // return a blank linear layout as the default action
        }
    }

}

StatCast.java

package com.pte.StatCast;

// imports

public class StatCast extends Activity {
/** Called when the activity is first created. */

    // Declare stuff

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // database stuff here

        /*
         * Swap in the pitch fragment when activity first loads
         */
        swapFragment(actionType.PITCH_ACTION);
    }

    private void swapFragment(int myType){

        Fragment f = new actionFragment(myType);

        // Execute a transaction, replacing any existing
        // fragment with this one inside the frame.
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.actionFragment, f);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.addToBackStack(null);
        ft.commit();

        Log.v("PTE", "COMPLETED: swapFragment");
    }
}

I'm still not entirely sure why the first attempt didn't work, but this method seems to me a little cleaner, and it works so I'm not complaining. If you have thoughts or comments, I'm still all ears to learn about this stuff. Thanks!

Peter
  • 808
  • 2
  • 11
  • 17
  • Hello I followed your code but I get errors about actiontype in both .java files: "actionType cannot be resolved to a variable" could you please help me? – Antonios Sep 02 '11 at 08:58