android fragment vs spinner onitemselected listener - android

i have a fragment with spinner in which i add data from internet
in onCreateView() i init my spinner and add listener for it
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, null);
cityChoose = (Spinner) view.findViewById(R.id.cityChoose);
cityChoose.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
HashMap temp = new HashMap();
temp.put("finset", cities.get(position).getValue());
HashMap map = new HashMap();
map.put("city", temp);
new DownloadData().execute(new Object[] { PARAM_DEALS_LIST,
map, getStoreID(), "1", "15" });
}
}
Then in on onCreate i first add data to spinner
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Tools.isNetworkAvailable(getActivity().getApplicationContext())) {
new DownloadData().execute(new Object[] { PARAM_BOTH, "",
getStoreID(), "1", "15" });
} else {
Toast.makeText(getActivity(),
getResources().getString(R.string.toastNoInternet),
Toast.LENGTH_SHORT).show();
}
}
Then if user go from this fragment to another fragment and click back button from it i need to show in spinner my data that i was add early i do this in such way
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (spinAdapter != null) {
cityChoose.setAdapter(spinAdapter);
}
}
And my problem is this:
If i first go to the fragment, spinner will download data and filled with it by adapter, then if i go to another fragment and then push back button the spinner will get data from adapter, all works good, but if i in fragment with spinner click on one of its items and then go to another fragment and went back it will init its onItemSelected() method and download data one more time, but the adapter already has this data.
How i can avoid initing onItemSelected() in spinner when i back to this fragment from another ?

Related

How to stop onItemSelected from getting executed when returning from a locked screen

I have just one fragment attached to an activity using replace. When the device locks the screen after a few seconds and then I unlock it, the onItemSelected method assigned to some spinner gets executed, even though the fragment views (EditTexts and so) and the spinner selected item remains the same.
public class MyFragment extends Fragment {
private Spinner mySpinner;
public static MyFragment newInstance() {
return new MyFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.some_layout, container, false);
mySpinner = (Spinner)view.findViewById(R.id.my_spinner);
List<String> items = new ArrayList<>();
items.add("Anything");
items.add("Anything");
items.add("Anything");
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
getContext(),
android.R.layout.simple_spinner_item,
items);
mySpinner.setAdapter(adapter);
mySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(getContext(), "Hello World", Toast.LENGTH_LONG).show();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return view;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
Every time I select an item I get the toast message "Hello World" (or any other method or action assigned to the listener), but when the device locks and then I unlock, I'm still getting the message as if the method onItemSelected was called.
I've been trying to mess around with booleans and Fragment's onSaveInstanceState and onActivityCreated methods, but I haven't figured out a way to stop onItemSelected method from executing when the device returns from a locked screen.
The problem is that onItemSelected is called after Spinner is initialised, solution is to put mySpinner.setSelection(position, false) before mySpinner.setOnItemSelectedListener
refer to this

My activity enters twice in onCreateView() and it resets my saved variables

I was having some problems with an activity from my app.
I was saving some data with onSavedInstanceState() and restoring in onCreateView() method (this activity has two fragments and it has onCreate an onCreateView). The data restored were corrected but I could not put them correctly in a spinner from my activity.
I have put some breakpoints before, within and after at this loop:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item, list);
spinner.setAdapter(adapter);
**if(savedInstanceState != null) {
Log.i("SPINNER POS", ""+posSaved);
spinner.setSelection(posSaved);
}**
and I have could observer that the app access twice to onCreateView method ... the first time the posSaved variable is correct, but the second time this variable is 0 and due to this reason the spinner never shows the position saved in posSaved variable, always it shows the 0 position (like by default) and then is like I do not use onSavedInstanceState method ...
... why app enter twice in onCreateView() method? How can I solve this situation?
PD. This activity also enters twice in onCreate() method.
My Activity CODE
public class Menu_Seeker_Filter extends Fragment {
... (variables declarated) ...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((getFragmentManager().findFragmentById(R.id.results_fragment) != null)) { //Fragments
mTwoPane = true;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_seeker_filtro, container, false);
if (savedInstanceState != null) {
// Restore value of members from saved state
posSaved = savedInstanceState.getInt("POSITION");
}
...
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item, list);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
((TextView) parent.getChildAt(0)).setTextSize(18);
((TextView) parent.getChildAt(0)).setTypeface(font2);
text = (parent.getItemAtPosition(pos).toString());
posSaved = pos;
}
public void onNothingSelected(AdapterView<?> parent) {
//Do nothing.
}
});
if(savedInstanceState != null) {
Log.i("POSITION", ""+posSaved);
spinner.setSelection(posSaved);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt("POSITION", spinner.getSelectedItemPosition());
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
}
and this activity-fragment is called in this class:
public class Menu_Seeker extends FragmentActivity {
...(variables declarated)...
final Menu_Seeker_Filter fragment = new Menu_Seeker_Filter();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_seeker_filter);
if ((getSupportFragmentManager().findFragmentById(R.id.results_fragment) != null)) { //Fragments
mTwoPane = true;
getSupportFragmentManager().beginTransaction().replace(R.id.seeker_fragment, fragment).commit();
}else { //No Fragments
getSupportFragmentManager().beginTransaction().replace(R.id.framelayout_filter, fragment).commit();
}
...
}
Thanks.

Best way to fill a list with an adapter in a fragment

I developed an app which fills a list. It works fine in the way I did it but I'm not conviced that I solved the problem in a recommended way. I read that you should override onActivityCreated in a Fragment and fill the list there instead of doing this in onCreateView. onCreateView should only be used to inflate static views. Is this true? If yes, how should these two methods look like in the end?
This is my Fragment class:
public class FragmentMain extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
List<MyItem> items = createListItems();
ListView listView = (ListView) view.findViewById(R.id.list);
MyListAdapter adapter = new MyListAdapter(view.getContext(), items);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(),
"Clicked " + position, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
.
.
.
}
My MainActivity just adds the fragment:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentMain fm = new FragmentMain();
getFragmentManager().beginTransaction()
.add(R.id.fragment_main_container, fm).commit();
}
.
.
.
}
That is true to a certain extend only because onCreateView happens on the UI thread and you don't want anything slowing that down otherwise your UI will be slow and choppy. For example, in your fragment class you have a call to a method "createListItems()". I don't know how many items you're making but if it's a lot it could slow down your UI (especially if youre accessing a database and querying objects and so on). So you could do it in onActivityCreated but you could also use an AsyncTask. So your code would become something like this:
public class LoadListObjectsTask extend AsyncTask<Void, List<MyItem>, Void> {
private MyListAdapter myListAdapter;
private Context mContext;
public LoadListObjectsTask(Context context) {
this.mContext = context;
}
#Override
public void doInBackground(Void...params) {
//create your list objects here instead of on UI thread. This will run on a separate thread.
myListAdapter = new MyListAdapter(mContext, items);
return items; //return list of MyItems
}
//This is called when doInBackground is done. THIS WILL RUN ON THE UI THREAD So don't do
//anything slow here
#Override
public void onPostExecute(List<MyItem>...params //don't really need the list here//) {
listView.setAdapter(myListAdapter);
}
}
then in your fragment
public class FragmentMain extends Fragment {
private ListView listView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
List<MyItem> items = new ArrayList<MyItem>();
listView = (ListView) view.findViewById(R.id.list);
//new code
new LoadListObjectsTask(getActivity()).execute();
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(),
"Clicked " + position, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
public void onResume()... {
//also add the task here so your content is reloaded on resume..
new LoadListObjectsTask(getActivity()).execute();
}
.
.
.
}
If you don't want to do this just make your List of MyItems a private field and move
List<MyItem> items = createListItems();
to onActivityCreated().
Hope that helps!

Refreshing Fragment

I'm developing an app that uses fragment. In one of these fragments I retrieve data from a remote server and populate a listview. But I noticed that if a user inserts a new value and then goes back to the fragment it doesn't show it. The fragment shows the new value only after the user closes and reopens the app... How can I solve it? I need a way to refresh the fragment every time the user swipes and views it...
This is the code:
public class Page2Fragment extends Fragment {
TestImmagineAdapter adp2;
Archivio archivio;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// fragment not when container null
if (container == null) {
return null;
}
// inflate view from layout
View view = (LinearLayout)inflater.inflate(R.layout.page2,container,false);
ListView mylist = (ListView) view.findViewById(R.id.listView);
archivio = new Archivio();
adp2 = new TestImmagineAdapter(archivio.retTitle(), archivio.retArt(), this.getActivity().getApplicationContext());
mylist.setAdapter(adp2);
/*mylist.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Intent service = new Intent(view.getContext(), Web.class);
service.putExtra("href", archivio.getLink(position));
startActivity(service);
// TODO Auto-generated method stub
}
});*/
return view;
}
}
You need to notify your adapter of the change.
On the update of your data you use:
adp2.notifyDataSetChanged();

arrayadapter.clear() deletes underlying data

i got the following Problem. I got a listview and two buttons. At the start of the Fragment some data is stored in 2 Arraylists. At first the content of the first Arraylist is shown in the listview which works fine. When the use clicks the first button the ListView shows the second ArrayList. Which works fine for the user but as soon as i call adapter.clear(). The first Arraylist got deleted. Therefor he cant switch back to the first list by clicking on the first button. I never delete the Arraylist so i wonder why adapter.clear() does it. Any help would be nice. Code underneath.
public class MessagesFragment extends Fragment {
private ArrayList<Message> outbound;
private ArrayList<Message> inbound;
private MessageAdapter messageadapter;
private int box;
private View rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_messages, container,
false);
outbound = new ArrayList<Message>();
inbound = new ArrayList<Message>();
this.rootView = rootView;
box = 0;
messageadapter = new MessageAdapter(getActivity(),
R.layout.item_message, inbound);
((ListView) rootView.findViewById(R.id.lv_message))
.setAdapter(messageadapter);
initializeListeners();
return rootView;
}
private void initializeListeners() {
rootView.findViewById(R.id.rb_message_inbox).setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
showBox(0);
}
});
rootView.findViewById(R.id.rb_message_outbox).setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
showBox(1);
}
});
}
private void showBox(int box) {
messageadapter.clear();
switch (box) {
case 0:
messageadapter.addAll(inbound);
break;
case 1:
messageadapter.addAll(outbound);
break;
}
this.box = box;
messageadapter.notifyDataSetChanged();
}
}
So at the beginning the list gets populated with the ArrayList inbound. But when showbox(1) is called inbound gets deleted as soon as messageadapter.clear() gets called.
iutbound will be shown but with calling showbox(0) after that inbound wont because its empty.
This happened because your class member arraylist is the same reference as you set into your adapter. Add data to your adapter by
adapter.addAll(new ArrayList<Message>(inbound);

Categories

Resources