如何添加带有片段的新选项卡

时间:2015-07-08 20:14:11

标签: android android-fragments tabs nullpointerexception

所以我想创建3个标签,彼此不同。我覆盖的xml。但不是如何在不崩溃我的应用程序的情况下创建选项卡。

我已经使用viewpage实现了滑动选项卡。

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

和部分 http://www.java2s.com/Code/Android/UI/Demonstrateshowfragmentscanparticipateintheoptionsmenu.htm

当我尝试转到下一个标签时(滑动确实没问题)我收到错误:

    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)

那么......我在这里做错了什么?我可以看到我的创建圆片段有一个空引用...但我不知道如何解决这个问题。这是我第一次使用片段和标签。

代码: 主要活动:

    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);
}


}

其中一个片段(其他片段尚未包含太多代码):

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();
            }
        }

}

编辑:

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;
    }

}

编辑2:

我跟着将数据传递给活动,这确实有效,但是如果我想从活动传递数据(从addPlayerTab获取数据)我再次得到一个空引用,这次我认为是因为id错了。但我的布局文件不使用。那么我将如何找到片段呢?

代码: addPlayerTab的接口实现:

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

}

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();
        }

    }

这是用于将数据传递到createroundtab的接口实现:

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

    createRoundfragmentTab.makeRandomFirstRound(players);
}
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");
        }
    }

2 个答案:

答案 0 :(得分:1)

您没有初始化片段的viewPager字段(addPlayersfragmentTab.viewPager)。这就是你得到NullPointerException的原因。

您可以在活动中执行getViewPager()方法,然后在片段中调用它,即((CreateDraft) getActivity()).getViewPager().setCurrentItem(1)

答案 1 :(得分:1)

我已经在上面的Fragment实例中分享了我的观点,所以我再次引用自己。

  

不需要整个if (savedInstance == null)块,因为Fragment实例化是PagerAdapter的工作。如果ViewPager认为合适,PagerAdapter#getItem()会调用NullPointerException

尽管ViewPager是由addPlayersfragmentTab中未初始化的Fragment引用引起的,但是将视图寻呼机传递给片段的整个方法相当明显在创建或通过getter访问它的片段是错误的。

原因是片段是UI的一部分的自包含可重用实现,因此它不应该与托管它的活动结合起来。将视图寻呼机与视图寻呼机耦合后,您再也无法在任何其他正常活动中托管此片段。简而言之,片段不再可以重复使用。

那么,一个片段应该如何与其主机活动进行通信?好吧,使用回调接口。以下是来自官方Android开发者网站的简短教程:Communicating with Other Fragments但是它可以用于请求活动代表片段执行任何操作。

在您的情况下,您会通知主要活动,用户在警告对话框中按了OK,活动将通过使用视图寻呼机移动到下一个选项卡来响应。

通常,当您想再次抓住findFragmentById()时,可以使用findFragmentByTag()或其自定义标记ViewPager。但是,整个PagerAdapter及其PagerAdapter并未向我们公开这些属性。

因此,要启用片段查找,您需要在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; } 中保留对它们的引用。类似于以下内容。

GetPlayer()

通过上述更改,您的@Override public void GetPlayer() { createRoundfragmentTab createRoundfragmentTab = (createRoundfragmentTab) ((fragmentPageAdapter) mAdapter).getFragment("createRoundfragmentTab"); createRoundfragmentTab.makeRandomFirstRound(players); } 实施现在将变为

ALTER TABLE tblName AUTO_INCREMENT = 1000;

要详细了解此方法,请阅读ViewPager and fragments — what's the right way to store fragment's state?

另外,请同时查看Oracle推荐的Java naming conventions。简而言之,您需要使用大写字母开始您的类名,并使用您的方法名称执行相反的操作。遵循这些约定将使您的代码更容易阅读,从而更容易理解。目前,所有类名都显示为经验丰富的Java开发人员的变量名。