1

So I want to create 3 tabs, all different from each other. The xml I have that covered. But not how to create the tabs without it crashing my app.

I have implemented the swipe tab with viewpage.

http://developer.android.com/training/implementing-navigation/lateral.html http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/

and part of http://www.java2s.com/Code/Android/UI/Demonstrateshowfragmentscanparticipateintheoptionsmenu.htm

When I try to go to the next tab(swipe does work no problem) I get an error:

    07-08 22:07:57.414: E/AndroidRuntime(6865): FATAL EXCEPTION: main
07-08 22:07:57.414: E/AndroidRuntime(6865): Process: com.cyberdog.magiceasydraft, PID: 6865
07-08 22:07:57.414: E/AndroidRuntime(6865): java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.view.ViewPager.setCurrentItem(int)' on a null object reference
07-08 22:07:57.414: E/AndroidRuntime(6865):     at com.cyberdog.magiceasydraft.addPlayersfragmentTab.doPositiveClick(addPlayersfragmentTab.java:113)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at com.cyberdog.magiceasydraft.addPlayersfragmentTab$MyAlertDialogFragment$1.onClick(addPlayersfragmentTab.java:165)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:160)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at android.os.Handler.dispatchMessage(Handler.java:102)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at android.os.Looper.loop(Looper.java:135)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at android.app.ActivityThread.main(ActivityThread.java:5274)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at java.lang.reflect.Method.invoke(Native Method)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at java.lang.reflect.Method.invoke(Method.java:372)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
07-08 22:07:57.414: E/AndroidRuntime(6865):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)

So.. what am I doing wrong here? I can see that there is a null reference to my create round fragment... but I have no clue how to fix this. This is my first time working with fragments and tabs.

code: main activity:

    public class CreateDraft extends FragmentActivity implements
        ActionBar.TabListener {

    private ViewPager viewPager;
    private fragmentPageAdapter mAdapter;
    private ActionBar actionBar;
    private Fragment addPlayer, createRound,score;
    private String[] tabs = { "Add players", "Create round", "Score" };
    public static final String CuSToM_FRAGMENT_KEY ="ADD_PLAYER_TAB";



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create_draft);



        viewPager = (ViewPager) findViewById(R.id.activity_viewpager_main);
        actionBar = getActionBar();
        mAdapter = new fragmentPageAdapter(getSupportFragmentManager());

        viewPager.setAdapter(mAdapter);
        actionBar.setHomeButtonEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        if(savedInstanceState == null){
            FragmentManager fm = getSupportFragmentManager();
            android.support.v4.app.FragmentTransaction ft = fm.beginTransaction();

            addPlayer = fm.findFragmentByTag("Add Players");
            if(addPlayer == null){
                addPlayer = new addPlayersfragmentTab();
                ft.add(addPlayer, "Add players");
            }

            createRound = fm.findFragmentByTag("Create round");
            if(createRound == null){
                createRound = new createRoundfragmentTab();
                ft.add(createRound, "Create round");
            }


            score = fm.findFragmentByTag("Score");
            if(score == null){
                score = new scoreResultfragmentTab();
                ft.add(score, "Score");
            }

            ft.commit();
        }

//      
        for (String tab_name : tabs) {
            actionBar.addTab(actionBar.newTab().setText(tab_name)
                    .setTabListener(this));
        }



        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                // on changing the page
                // make respected tab selected
                actionBar.setSelectedNavigationItem(position);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
            }
        });

    }

    public void passBundleToFragment(int position){
        if(true){

        }

    }


    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        View focus = getCurrentFocus();
        if (focus != null) {
            hiddenKeyboard(focus);
        }

    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // on tab selected
        // show respected fragment view
        viewPager.setCurrentItem(tab.getPosition());
        View focus = getCurrentFocus();
        if (focus != null) {
            hiddenKeyboard(focus);
        }

    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        View focus = getCurrentFocus();
        if (focus != null) {
            hiddenKeyboard(focus);
        }

    }

private void hiddenKeyboard(View v) {
    InputMethodManager keyboard = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    keyboard.hideSoftInputFromWindow(v.getWindowToken(), 0);
}


}

One of the fragments(others don't contain much code yet):

public class addPlayersfragmentTab extends Fragment {

    private Button addPlayer, createDraft;
    private EditText evAddPlayer;
    private ViewPager viewPager;
    private List<Player> players;
    private ListView lvAddedPlayers;
    ListAdapter adapter;
    private boolean buttonCreateDraftPressed= false;

    public boolean isButtonCreateDraftPressed() {
        return buttonCreateDraftPressed;
    }

    public void setButtonCreateDraftPressed(boolean buttonCreateDraftPressed) {
        this.buttonCreateDraftPressed = buttonCreateDraftPressed;
    }

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

        View rootView = inflater.inflate(R.layout.draft_adding_players,
                container, false);
        initialiseEditAndText(rootView);
        players = new ArrayList<Player>();

        lvAddedPlayers = (ListView) rootView.findViewById(
                R.id.lv_players_adding);
        adapter = new ListAdapter(rootView.getContext(), players);
        lvAddedPlayers.setAdapter(adapter);



        addPlayer = (Button) rootView.findViewById(R.id.button_total_player);
        createDraft = (Button) rootView.findViewById(R.id.button_create_draft);

        addPlayer.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                Player player = new Player(evAddPlayer.getText().toString());
                players.add(player);
                adapter.notifyDataSetChanged();
                InputMethodManager imm = (InputMethodManager) getActivity()
                        .getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);




                }
        });

        createDraft.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (adapter != null && players != null) {
                        createdraft(players.size());

                } else {
                    Toast.makeText(getActivity(),
                            "Add minimal 3 players to start the draft.",
                            Toast.LENGTH_LONG).show();
                }


            }
        });

        return rootView;

    }

    public void showDialog(){
        DialogFragment newFragment = new MyAlertDialogFragment().newInstance(R.string.recreate_draft);
        newFragment.show(getFragmentManager(), "dialog");
    }

    public void doPositiveClick(){
        viewPager.setCurrentItem(1);
    }

    public void doNegativeClick(){

    }


    public int getTotalPlayers() {
        return players.size();
    }

    public List<Player> getPlayersNames() {
        return players;
    }

    public void initialiseEditAndText(View rootView) {
        evAddPlayer = (EditText) rootView.findViewById(R.id.et_player_name);
    }

    public void createdraft(int totalplayers) {

        if (totalplayers >= 3 && totalplayers <= 16) {
            showDialog();

        } else {
            Toast.makeText(getActivity(),
                    "Minimum of 3 and maximum of 16 players.",
                    Toast.LENGTH_LONG).show();
        }

    }

    public class MyAlertDialogFragment extends DialogFragment{
        public MyAlertDialogFragment newInstance(int title){
            MyAlertDialogFragment frag = new MyAlertDialogFragment();
            Bundle args = new Bundle();
            args.putInt("title", title);
            frag.setArguments(args);
            return frag;
        }

         @Override
            public Dialog onCreateDialog(Bundle savedInstanceState) {
                int title = getArguments().getInt("title");

                return new AlertDialog.Builder(getActivity())
                        .setIcon(R.drawable.abc_ic_search)
                        .setTitle(title)
                        .setPositiveButton("R.string.alert_dialog_ok",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int whichButton) {
                                     addPlayersfragmentTab.this.doPositiveClick();
                                }
                            }
                        )
                        .setNegativeButton("R.string.alert_dialog_cancel",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int whichButton) {
                                       addPlayersfragmentTab.this.doNegativeClick();
                                }
                            }
                        )
                        .create();
            }
        }

}

EDIT:

pageadpter:

public fragmentPageAdapter(FragmentManager fm) {
        super(fm);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Fragment getItem(int index) {
        switch (index) {
        case 0:
            // Top Rated fragment activity
            return new addPlayersfragmentTab();
        case 1:
            // Games fragment activity
            return new createRoundfragmentTab();
        case 2:
            // Movies fragment activity
            return new scoreResultfragmentTab();
        }
        return null;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return 3;
    }

}

edit 2:

I followed the passing of data to the activity, that did work, however if I wanted to pass the data from the activity(that got the data from the addPlayerTab) i am getting a null reference again, this time i think becuase the id is wrong. but my layoutfile dont use . So how will i find the fragment?

code: the interface implementation of the addPlayerTab:

    @Override
public void onButtonClickCreateRound(int position, List<Player> players) {
    viewPager.setCurrentItem(position);
    this.players = players;
    GetPlayer();

}

code in addPlayerTab:

public interface GoToCreateRoundListener{
        public void onButtonClickCreateRound(int position, List<Player> players);
    }

    public void onAttach(Activity activity){
        super.onAttach(activity);

        try{
            goCreateRound = (GoToCreateRoundListener)activity;
        }catch(ClassCastException e){
            throw new ClassCastException(activity.toString()+" must implement GoToRoundListener");
        }
    }

    public void createdraft(int totalplayers) {

        if (totalplayers >= 3 && totalplayers <= 16) {
            goCreateRound.onButtonClickCreateRound(1, players);

        } else {
            Toast.makeText(getActivity(),
                    "Minimum of 3 and maximum of 16 players.",
                    Toast.LENGTH_LONG).show();
        }

    }

this is the interface implementation for passing the data to the createroundtab:

@Override
public void GetPlayer() {
    createRoundfragmentTab createRoundfragmentTab = (createRoundfragmentTab)getSupportFragmentManager().findFragmentById(R.layout.create_round);

    createRoundfragmentTab.makeRandomFirstRound(players);
}

code in the createroundTab:

public interface GetPlayersFromAddPlayersListener{
        public void GetPlayer();
    }

    public void onAttach(Activity activity){
        super.onAttach(activity);

        try{
            getPlayers = (GetPlayersFromAddPlayersListener)activity;
        }catch(ClassCastException e){
            throw new ClassCastException(activity.toString()+" must implement GetPlayersFromAddPlayersListener");
        }
    }
Litisqe Kumar
  • 2,512
  • 4
  • 26
  • 40
cc2k
  • 351
  • 1
  • 2
  • 12

2 Answers2

1

You didn't initialize viewPager field of your fragment (addPlayersfragmentTab.viewPager). That's why you got NullPointerException.

You can do getViewPager() method in activity and after that call it from fragment, i.e. ((CreateDraft) getActivity()).getViewPager().setCurrentItem(1)

Dmitry
  • 1,188
  • 13
  • 17
  • it seems like you are right, but somehow i cannot access the method.. i have made it public and not in the oncreate but outside of it but still i caanot call it from addPlayerTab with viewPager = (CreateDraft)getActivity()).getViewPager(); – cc2k Jul 08 '15 at 22:29
1

I've already shared my point on Fragment instantiation above so I'll just quote myself again.

That whole if (savedInstance == null) block is not required because Fragment instantiation is the job of your PagerAdapter. The ViewPager will call PagerAdapter#getItem() when it sees fit to.

Although, it's fairly obvious that the NullPointerException is caused by an uninitialized ViewPager reference inside your addPlayersfragmentTab, the whole approach of either passing the view pager to the fragment at creation or the fragment accessing it through a getter is wrong.

The reason is that a fragment is a self-contained reusable implementation of a part of your UI and hence it should not couple itself with the activity hosting it. Once you couple it with your view pager, you can never host this fragment in any other normal activity again. In short, the fragment does not remain reusable anymore.

So, then how is a fragment supposed to communicate with its host activity? Well, using Callback Interfaces. Here is a short tutorial from the official Android developers site: Communicating with Other Fragments but it works the same for requesting the activity to do anything on behalf of the fragment.

In your case, you would inform the main activity that the user pressed OK at the alert dialog and the activity would respond to that by moving to the next tab using the view pager.


Usually when you want to catch hold of a Fragment again, you either use findFragmentById() or its custom tag with findFragmentByTag(). But, the whole ViewPager and its PagerAdapter doesn't expose these properties to us.

So, to enable the fragment look-ups, you need to hold references to them inside your PagerAdapter. Something along the lines of the following.

Map<String, Fragment> mFragments = new HashMap<>(3);

...

@Override
public Fragment getItem(int index) {
    ...
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    // super calls getItem() if fragment is not already instantiated
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    mFragments.put(fragment.getClass().getSimpleName(), fragment);
    return fragment;
}

public Fragment getFragment(String name) {
    return mFragments.get(name);
}

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

With the above changes, your GetPlayer() implementation would now become

@Override
public void GetPlayer() {
    createRoundfragmentTab createRoundfragmentTab = (createRoundfragmentTab)
            ((fragmentPageAdapter) mAdapter).getFragment("createRoundfragmentTab");

    createRoundfragmentTab.makeRandomFirstRound(players);
}

To understand this approach in more details please do read ViewPager and fragments — what's the right way to store fragment's state?.

As an aside, please also take a look at Java naming conventions recommended by Oracle. Long story short, you need to start your class names with an upper case letter and do the opposite with your method names. Following these conventions would make your code easier to read and thus more understandable. Currently, all your class names appear as variable names to seasoned Java developers.

Community
  • 1
  • 1
Ravi K Thapliyal
  • 51,095
  • 9
  • 76
  • 89
  • i added another update to it, as i got another nullpointer error when i try passing data from addPlayerTab-->activity---->createRoundTab. and i believe it is from the findfragment part, as i use layoutfiles for the fragments, not . How could i solve that? – cc2k Jul 09 '15 at 11:09
  • 1
    @cc2k Added an update on how to save and retrieve fragment references. – Ravi K Thapliyal Jul 09 '15 at 17:06
  • your solution worked, except i needed to cast it like this: createRoundfragmentTab createRoundfragmentTab = (createRoundfragmentTab) ((fragmentPageAdapter)mAdapter).getFragment("createRoundfragmentTab"); – cc2k Jul 10 '15 at 01:00
  • 1
    @cc2k Oh yes, it's needed. Since I was directly editing your code here, I missed that. – Ravi K Thapliyal Jul 10 '15 at 07:17