ArrayList Double his size each time I come back to the fragment

时间:2018-10-02 09:13:48

标签: java android fragment bundle

I'm a new Android Developer and I tried to create some Tourist App"

In my app I have the HomeFragment which have 3 Buttons: "Attractions" "Events" "Hotels"

public class HomeFragment extends Fragment implements View.OnClickListener {

private ArrayList<Category> mAttractions= new ArrayList<>();
private ArrayList<Category> mEvents= new ArrayList<>();
private ArrayList<Category> mHotels= new ArrayList<>();


private int mAttractionsBtnId = R.id.attractions_btn;
private int mEventsBtnId = R.id.events_btn;
private int mHotelsBtnId = R.id.hotels_btn;

public HomeFragment() {
    // Required empty public constructor
}

public void initCategoriesData() {
    // init attraction array list
    mAttractions.add(new Category("Jaffa Port",5,R.drawable.attractions_jaffa_port));
    mAttractions.add(new Category("Beit Hatfusot",5,R.drawable.attractions_beit_hatfutsot));

    mAttractions.add(new Category("Independence Hall",5,R.drawable.attractions_independence_hall));

    mAttractions.add(new Category("Jaffa Bazar",5,R.drawable.attractions_jaffa_bazar));

    mAttractions.add(new Category("Neve Tzedek St",5,R.drawable.attractions_neve_tzedek));

    mAttractions.add(new Category("Rothschild Boulevard St",5,R.drawable.attractions_rothschild_boulevard));


    // init Events array list
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));
    mEvents.add(new Category("cacdas",3));

    // init Hotels array list
    mHotels.add(new Category("hotels",3));
    mHotels.add(new Category("hotels",3));
    mHotels.add(new Category("hotels",3));
    mHotels.add(new Category("hotels",3));
    mHotels.add(new Category("hotels",3));
    mHotels.add(new Category("hotels",3));




}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_home, container, false);

    // Initiate data for each category
    initCategoriesData();


    // Find Buttons
    Button attractionsBtn = (Button)view.findViewById(R.id.attractions_btn);
    Button hotelsBtn = (Button)view.findViewById(R.id.hotels_btn);
    Button eventsBtn = (Button)view.findViewById(R.id.events_btn);

    // Set buttons OnClickListener
    attractionsBtn.setOnClickListener(this);
    hotelsBtn.setOnClickListener(this);
    eventsBtn.setOnClickListener(this);


    return view;
}


@Override
public void onClick(View v) {
    // Start new Fragment when Button Clicked
    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction().addToBackStack(null);

    Bundle bundle = new Bundle();


    // Pass the right data in the bundle
    switch (v.getId()){
        case R.id.attractions_btn:
            bundle.putSerializable("Data",mAttractions);
            break;

        case R.id.hotels_btn:
            bundle.putSerializable("Data",mHotels);
            break;

        case R.id.events_btn:
            bundle.putSerializable("Data",mEvents);
            break;

    }

    ArrayList<Category> cat = (ArrayList<Category>)bundle.getSerializable("Data");
    int size = cat.size();

    MasterFragment masterFragment = new MasterFragment();
    masterFragment.setArguments(bundle);

    fragmentTransaction.replace(R.id.fragment_container, masterFragment);
    fragmentTransaction.commit();
}

}

because all the content is the same ( just the category name is different) I decided to use MasterFragment in order to no duplicate the code for each Category.

All of the "Data" is created in the HomeFragment, and each time the used click on one of the button's, the app create new MasterFragment and send him the data inside a Bundle in order to let him know which data he needs to show.

This is how the "MasterFragment" looks like:

public class MasterFragment extends Fragment {

private ArrayList<Category> mData;

public MasterFragment() {
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle bundle) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.item_list, container, false);
    mData = (ArrayList<Category>)getArguments().getSerializable("Data");

    // Create an {@link WordAdapter}, whose data source is a list of {@link Category}s. The
    // adapter knows how to create list items for each item in the list.
    CategoryAdapter adapter = new CategoryAdapter(getActivity(), mData, R.color.colorAccent);

    // Find the {@link ListView} object in the view hierarchy of the {@link Activity}.
    // There should be a {@link ListView} with the view ID called list, which is declared in the
    // word_list.xml layout file.
    ListView listView = (ListView) rootView.findViewById(R.id.list);

    // Make the {@link ListView} use the {@link WordAdapter} we created above, so that the
    // {@link ListView} will display list items for each {@link Word} in the list.
    listView.setAdapter(adapter);


    return rootView;
}

}

Everything is work fine, when the user click for example the AttractionButton, the app show the content great(Only the design is bad lol) But!! when I clicked the 'back button' and return to the HomeFragment and then click again on the AttractionButton it duplicate the Arraylist (from 6 items to 12 and so on...)

I fixed the issue by init the ArrayList variables inside the "initCategoriesData" method

But I still dont understand why the app act the way she did I appreciate a good explanation on this it will really help me understand better the way thing works

Thank in advance, Niv :)

5 个答案:

答案 0 :(得分:2)

因为您的碎片不会被破坏,并且当您返回时,您的arraylist已经有6个项目(因为未重新创建碎片)。因此,您还要再添加6个项目,arraylist的大小将变为12。您可以通过类似方法来解决此问题。

private ArrayList<Category> mAttractions;
private ArrayList<Category> mEvents;
private ArrayList<Category> mHotels;

public void initCategoriesData() {

//initialize array list here

mAttractions= new ArrayList<>()
mEvents= new ArrayList<>();
mHotels= new ArrayList<>();

// init attraction array list
mAttractions.add(new Category("Jaffa Port",5,R.drawable.attractions_jaffa_port));
mAttractions.add(new Category("Beit Hatfusot",5,R.drawable.attractions_beit_hatfutsot));

mAttractions.add(new Category("Independence Hall",5,R.drawable.attractions_independence_hall));

mAttractions.add(new Category("Jaffa Bazar",5,R.drawable.attractions_jaffa_bazar));

mAttractions.add(new Category("Neve Tzedek St",5,R.drawable.attractions_neve_tzedek));

mAttractions.add(new Category("Rothschild Boulevard St",5,R.drawable.attractions_rothschild_boulevard));


// init Events array list
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));
mEvents.add(new Category("cacdas",3));

// init Hotels array list
mHotels.add(new Category("hotels",3));
mHotels.add(new Category("hotels",3));
mHotels.add(new Category("hotels",3));
mHotels.add(new Category("hotels",3));
mHotels.add(new Category("hotels",3));
mHotels.add(new Category("hotels",3));

}

希望它对您有所帮助。

答案 1 :(得分:0)

每次返回HomeFragment时,都会调用OnCreateView方法,同时也会调用initCategoriesData(),因为正在重新创建视图。尝试将函数放在其他位置,onCreate()应该没问题

答案 2 :(得分:0)

//尝试一下。 当您不清除列表之前,就向其中添加数据。 请清除您的列表,因为我已经在您的代码中对此进行了更新。

   public class HomeFragment extends Fragment implements View.OnClickListener {

        private ArrayList<Category> mAttractions= new ArrayList<>();
        private ArrayList<Category> mEvents= new ArrayList<>();
        private ArrayList<Category> mHotels= new ArrayList<>();


        private int mAttractionsBtnId = R.id.attractions_btn;
        private int mEventsBtnId = R.id.events_btn;
        private int mHotelsBtnId = R.id.hotels_btn;

        public HomeFragment() {
            // Required empty public constructor
        }

        public void initCategoriesData() {
            // init attraction array list
       mAttractions.clear();
       mEvents.clear();
       mHotels.clear();
            mAttractions.add(new Category("Jaffa Port",5,R.drawable.attractions_jaffa_port));
            mAttractions.add(new Category("Beit Hatfusot",5,R.drawable.attractions_beit_hatfutsot));

            mAttractions.add(new Category("Independence Hall",5,R.drawable.attractions_independence_hall));

            mAttractions.add(new Category("Jaffa Bazar",5,R.drawable.attractions_jaffa_bazar));

            mAttractions.add(new Category("Neve Tzedek St",5,R.drawable.attractions_neve_tzedek));

            mAttractions.add(new Category("Rothschild Boulevard St",5,R.drawable.attractions_rothschild_boulevard));


            // init Events array list
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));
            mEvents.add(new Category("cacdas",3));

            // init Hotels array list
            mHotels.add(new Category("hotels",3));
            mHotels.add(new Category("hotels",3));
            mHotels.add(new Category("hotels",3));
            mHotels.add(new Category("hotels",3));
            mHotels.add(new Category("hotels",3));
            mHotels.add(new Category("hotels",3));




        }


        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.fragment_home, container, false);

            // Initiate data for each category
            initCategoriesData();


            // Find Buttons
            Button attractionsBtn = (Button)view.findViewById(R.id.attractions_btn);
            Button hotelsBtn = (Button)view.findViewById(R.id.hotels_btn);
            Button eventsBtn = (Button)view.findViewById(R.id.events_btn);

            // Set buttons OnClickListener
            attractionsBtn.setOnClickListener(this);
            hotelsBtn.setOnClickListener(this);
            eventsBtn.setOnClickListener(this);


            return view;
        }


        @Override
        public void onClick(View v) {
            // Start new Fragment when Button Clicked
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction().addToBackStack(null);

            Bundle bundle = new Bundle();


            // Pass the right data in the bundle
            switch (v.getId()){
                case R.id.attractions_btn:
                    bundle.putSerializable("Data",mAttractions);
                    break;

                case R.id.hotels_btn:
                    bundle.putSerializable("Data",mHotels);
                    break;

                case R.id.events_btn:
                    bundle.putSerializable("Data",mEvents);
                    break;

            }

            ArrayList<Category> cat = (ArrayList<Category>)bundle.getSerializable("Data");
            int size = cat.size();

            MasterFragment masterFragment = new MasterFragment();
            masterFragment.setArguments(bundle);

            fragmentTransaction.replace(R.id.fragment_container, masterFragment);
            fragmentTransaction.commit();
        }

答案 3 :(得分:0)

由于您正在使用fragmentTransaction.replace(),因此每次返回时都会调用HomeFragment.onCreate()HomeFragment.onCreateView()。因此initCategoriesData()也将被调用。您可以每次从头开始清除并初始化所有数据,或者使用fragmentTransaction.add()而不是fragmentTransaction.replace()来避免此问题。

fragmentTransaction.replace()换出您当前的片段。它不再附加到活动,但是Fragment对象仍然有效,并且存储在变量中的所有数据仍然存在。当您将其带回活动时,它分别调用onCreate()onCreateView()来重新创建其视图。 这些操作会在您replace()并返回时发生:

  1. HomeFragment消失
  2. MasterFragment来了
  3. MasterFragment消失
  4. HomeFragment回来,触发onCreate()onCreateView()

fragmentTransaction.add()的行为就像在当前Fragment的顶部添加另一个Fragment一样,而无需将其移开。当您返回时,它只会显示原始的Fragment,它一直坐在那儿而没有任何动作。这些动作会在您add()并返回

时发生
  1. MasterFragment来了,涵盖了HomeFragment
  2. MasterFragment消失,露出HomeFragment

HomeFragment基本上没有被触及,因此没有触发任何动作。

答案 4 :(得分:0)

Android developers看到上面的图像,当用户通过按下后退按钮发现片段时,将调用onCreateView()。然后进行initCategoriesData()

片段从后堆栈返回到布局,然后调用onCreateView()initCategoriesData()