1

I've written a game where the user inputs the number of player and every player gets an own tab with an empty table.

Therefore I used a PagerAdapterClass (extends FragmentStatePagerAdapter) and a viewpager. So every player has the same fragmentView.

Now the user can put variables into the table, bu everytime I switch between the tabs, the input gets lost. Well, i 'fixed' that problem by adding this to my pageradapter:

@Override
    public void destroyItem(ViewGroup container, int position, Object object) {

    }

But it's more stopping the viewpager from destroying than actually saving the data.

My main goal is to really save that stuff in that table.

I already tried https://stackoverflow.com/a/17135346/11956040 but i cannot get mContent because i cannot get the reference of the fragment, because all fragments are not created on their own but all at the same time (or something like that).

I also don't know how to set a Tag. This way: https://stackoverflow.com/a/18993042/11956040 doesn't work for me.

MainActivity:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);
        Toolbar toolbar = findViewById(R.id.toolbar2);
        setSupportActionBar(toolbar);

        ...

        //numPlayer = num of tabs
        SectionsPagerAdapter adapter = new SectionsPagerAdapter(numPlayer, getSupportFragmentManager());

        ViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(adapter);

        TabLayout tabs = findViewById(R.id.tabs);
        tabs.setupWithViewPager(viewPager);
        if(numPlayer >= 5) {
            tabs.setTabMode(TabLayout.MODE_SCROLLABLE);
        }
    }

PagerAdapter:

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {

    private int tabNum;

    public SectionsPagerAdapter(int tabNum, FragmentManager fm) {
        super(fm);
        this.tabNum = tabNum;
    }

    @Override
    public PlaceholderFragment getItem(int position) {
        return PlaceholderFragment.newInstance(position);
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        int playerNum = position + 1;
        return "Spieler " + playerNum;
    }

    @Override
    public int getCount() {
        // Show 2 total pages.
        return tabNum;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {

    }
}

Fragment:

public static PlaceholderFragment newInstance(int index) {
        PlaceholderFragment fragment = new PlaceholderFragment();
        Bundle bundle = new Bundle();
        bundle.putInt("player", index);
        fragment.setArguments(bundle);
        return fragment;
    }

There must be a solution but I cannot find it or cannot implement it. Pls help.

Caetto
  • 43
  • 8
  • Just add this :ViewPager pager = (ViewPager) findViewById(R.id.viewPager); pager.setOffscreenPageLimit(2); – Kabir Aug 22 '19 at 13:32
  • @Kabir nice. But how exactly works that method? – Caetto Aug 22 '19 at 13:35
  • As per official document:setOffscreenPageLimit:Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed. – Kabir Aug 23 '19 at 04:10

1 Answers1

0

Solved my problem this way:

  1. define 2 dimensional ArrayList for rows and columns and counter for columns:
    private ArrayList<ArrayList<Integer>> columnArray; 
    private int column;
  1. onCreateView (for fragments) set column = 0 and add one entry with an empty list to columnArray and set the first rowList on column index of columnArray:
pointArray.add(column, new ArrayList<Integer>());
final ArrayList<Integer> rowList = pointArray.get(column);
  1. fill the empty rowListwith 0 (maybe it also works in an other way, but I made it this way to have on empty EditTexts a 0 and can easily replace them)

  2. define View.OnFocusChangeListener for all EditTexts like this:

/*I dont know if I could set column final in general, 
but you need to set a final int because you call this value in an inner class*/

final int pos = column 

for (int i = 0; i <= getEditTexts(pos).size() - 1; i++) {
EditText editTexts = getEditTexts(pos).get(i);
final String editTextsTag = editTexts.getTag().toString();

View.OnFocusChangeListener listener = new View.OnFocusChangeListener() {
   @Override
   public void onFocusChange(View view, final boolean b) {
      if (view.getTag().toString().equals(editTextsTag) && !b) {
        //fills rowList
        addEntries(pos, rowList);

        //adds rowList to columnArray
        columnArray.set(pos, rowList);

        //save the columnsArray or use it 
        saveData(columnArray);
      }
   }
};
editTexts.setOnFocusChangeListener(listener);
  1. define method which collects data from each cell, depending on column position (pos), add it to rowList for example:
private void addEntries(int pos, ArrayList<Integer> rowList) {
   for(int i = 0; i <= 16; i++) {
      //this requires EditText_label, i made them dynamically
      String edit_label = "edit_" + pos + i; 
      EditText editText = table.findViewWithTag(edit_label);
      String mEditTextString = editText.getText().toString();

      try {
         int thisValue = Integer.parseInt(mEditString);
         rowList.set(j, thisValue);
      } catch (NumberFormatException e) {
         //maybe you do not need this, but I need it for something else
         int thisValue = 0;
         rowList.set(j, thisValue);
      }
   }
}
  1. define a method for saving the columnArray. I used an interface to give it to parent Activity: Here you can find how I made it Otherwise you can convert the columnArray to a String and save it in a database.

NOTE

I made it with column value set beacuse I increase the value for every column I add during runtime using a method. If you just have one column, you dont need to set it. Just use 0 instead of pos, column

Caetto
  • 43
  • 8