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 :)
答案 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()
并返回时发生:
HomeFragment
消失MasterFragment
来了MasterFragment
消失HomeFragment
回来,触发onCreate()
和onCreateView()
fragmentTransaction.add()
的行为就像在当前Fragment
的顶部添加另一个Fragment
一样,而无需将其移开。当您返回时,它只会显示原始的Fragment
,它一直坐在那儿而没有任何动作。这些动作会在您add()
并返回
MasterFragment
来了,涵盖了HomeFragment
MasterFragment
消失,露出HomeFragment
HomeFragment
基本上没有被触及,因此没有触发任何动作。
答案 4 :(得分:0)
从Android developers看到上面的图像,当用户通过按下后退按钮发现片段时,将调用onCreateView()
。然后进行initCategoriesData()
。
片段从后堆栈返回到布局,然后调用onCreateView()
和initCategoriesData()
。