I am using a fragment activites. One of my activity has a spinner. I set its adapter. The problem is whenever I switch to that activity, spinner values increase. It actually adds the the same values into the spinner without removing the previous ones. How to solve it? my code is following:
public class AddPackageFragment extends Fragment {
View rootView;
EditText packageName;
EditText packageNumber;
Spinner network;
CheckBox sim1;
CheckBox sim2;
RadioGroup type;
RadioGroup through;
Button addPackage;
Button actDetails;
ArrayList<String> networks = new ArrayList<String>();
ArrayAdapter<String> adapter;
Context context;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.add_package, container, false);
initializeViews();
setNetworks();
setSpinner();
return rootView;
}
void initializeViews() {
packageName = (EditText)rootView.findViewById(R.id.pName);
packageNumber = (EditText)rootView.findViewById(R.id.pNumber);
network = (Spinner)rootView.findViewById(R.id.networkS);
sim1 = (CheckBox)rootView.findViewById(R.id.sim1);
sim2 = (CheckBox)rootView.findViewById(R.id.sim2);
type = (RadioGroup)rootView.findViewById(R.id.typeGroup);
through = (RadioGroup)rootView.findViewById(R.id.throughGroup);
addPackage = (Button)rootView.findViewById(R.id.addPackage);
actDetails = (Button)rootView.findViewById(R.id.activationDetails);
context = getActivity().getApplicationContext();
addPackage.setActivated(false);
actDetails.setActivated(false);
}
void setNetworks() {
networks.add("Mobilink");
networks.add("Telenor");
networks.add("Ufone");
networks.add("Warid");
networks.add("Zong");
networks.add("Add New");
}
void setSpinner() {
adapter = new ArrayAdapter<String>(context, R.layout.spinner_item, networks);
network.setAdapter(null);
network.setAdapter(adapter);
}
}
Try this:
void setNetworks() {
networks.clear()
networks.add("Mobilink");
networks.add("Telenor");
networks.add("Ufone");
networks.add("Warid");
networks.add("Zong");
networks.add("Add New");
}
I think it's because your array not cleared, not the spinner adapter.
To elaborate on #Dimmerg
Based on the Fragment lifecycle, your onCreateView will get called more than one time. So you have to take that into consideration and clear values (or Lists) accordingly.
Related
I have a ListFragment which fetches data from the net using a Loader. I use a new instance of this ListFragment in every page of my ViewPager. It works perfectly, but when I use TabLayout or moves pages quickly, the Fragment keeps loading and does not display the data in the ListView.
When I checked using log messages, I found that the ListFragment skips some lines of code in the onLoadFinished() method. It does not make the ProgressBar invisible. It does add items to Adapter, but it is not being displayed in the ListView. This problem also happens in the first page of the ViewPager.
Is there any specific rule to be followed when using ListFragments in a ViewPager?
Here is the ListFragment class. If you look at the onLoadFinished() method, you can see the lines causing problem:
public class ListViewFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<List<GameNews>> {
public static ListViewFragment newInstance(String url) {
Log.d("ListViewFragment", "newInstance created");
ListViewFragment f = new ListViewFragment();
// Supply url input as an argument.
Bundle args = new Bundle();
args.putString("url", url);
f.setArguments(args);
return f;
}
List<GameNews> TotalNews;
ListView gameListView;
LinearLayout emptyView;
Button retryButton;
ListAdapter adapter ;
private View progressBar;
final private int game_loader = 0;
ArrayList<String> urls = new ArrayList<>();
String mUrlString;
int index;
//LIFE CYCLE OF FRAGMENT
//------------------------------------------------------------------
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUrlString = getArguments().getString("url");
urls.add(mUrlString);
TotalNews = new ArrayList<GameNews>();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list_view, container, false);
ArrayList<GameNews> gameList = new ArrayList<>();
adapter = new ListAdapter(getActivity(), gameList);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
emptyView = (LinearLayout)
view.findViewById(R.id.no_internet_view);
progressBar = view.findViewById(R.id.progress_bar);
retryButton = (Button) view.findViewById(R.id.retry_button);
gameListView = getListView();
emptyView.setVisibility(View.INVISIBLE);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(adapter);
//If connected to net start the loader
if (isConnected()) {
getActivity().getSupportLoaderManager().restartLoader(game_loader,
null,
ListViewFragment.this);
}
}
//OVERRIDED METHODS OF LOADERMANAGER
//---------------------------------------------------------------------
#Override
public android.support.v4.content.Loader<List<GameNews>> onCreateLoader(int i, Bundle bundle) {
AdManager manager = new AdManager(getActivity());
return new FragmentLoader(getActivity(), urls, 1000);
}
//HERE IS THE PROBLEM PLEASE FOCUS INSIDE THIS METHOD
//-------------------------------------------------------
#Override
public void onLoadFinished(Loader<List<GameNews>> loader, List<GameNews> games) {
progressBar.setVisibility(View.INVISIBLE); //This line of code is not executed
adapter.clear();
TotalNews.addAll(games);
adapter.addAll(games);//And the listView is not populated
}
//-------------------------------------------------------
#Override
public void onLoaderReset(Loader<List<GameNews>> loader) {
adapter.clear();
}
//REUSABLE METHODS
//------------------------------------------------------------------
//Method checks if there is internet
public boolean isConnected() {
ConnectivityManager manager = (ConnectivityManager)
getActivity().getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
if (info != null && info.isConnected()) {
return true;
}
else {
return false;
}
}
}
Your Fragment class is using the Activity's LoaderManager:
getActivity().getSupportLoaderManager().restartLoader(...);
And each instance is using the same ID in its restartLoader() call:
final private int game_loader = 0;
This means that each Fragment instance was using and restarting the same Loader over and over again, leading to the weird behavior you observed.
The solution is quite simple: use Fragment's local LoaderManager, instead of the Activity's.
getLoaderManager().restartLoader(...);
With this, you don't need to worry about changing the ID in each instance, since Loaders are unique to their Fragment, and the Loader will be properly handled over the Fragment's lifetime, which would likely not have been the case when using the Activity's LoaderManager.
I have an Actiity where I have a simple Edittext and a button as shwown:
No I have a MainActivity which contains many fragments as shown:
This is my Code For passing edittext text to the main activity:
addlist = (ImageButton) findViewById(R.id.btnaddlist);
findViewById(R.id.btnaddlist).setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View arg0) {
EditText edit = (EditText) findViewById(R.id.txtlist);
Intent i = new Intent(CreateList.this,
MainActivity.class);
Bundle bundle = new Bundle();
String ItemName = edit.getText().toString();
// Add your data from getFactualResults method to bundle
bundle.putString("ListItemName", ItemName);
// Add the bundle to the intent
i.putExtras(bundle);
startActivity(i);
}
});
}
This is my Home fragment:
ListView lv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
lv = (ListView) getView().findViewById(R.id.itemslistView);
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
Bundle itemintent = getActivity().getIntent().getExtras();
String ItemName = itemintent.getString("ListItemName");
if (itemintent.getString("ListItemName").equals("ItemName")) {
/** Items entered by the user is stored in this ArrayList variable */
ArrayList<String> list = new ArrayList<String>();
list.add(ItemName);
/** Declaring an ArrayAdapter to set items to ListView */
ArrayAdapter<String> Listadapter;
Listadapter = new ArrayAdapter<String>(getActivity().getApplicationContext(),android.R.layout.simple_list_item_1, list);
Listadapter.notifyDataSetChanged();
}
return rootView;
}
I'm not getting any error in logcat..But its not able to add any text to listView on MainActivity.
You made the adapter but didn't call ListView#setAdapter()
Change your Home fragment like that:
ListView lv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
lv = (ListView) getView().findViewById(R.id.itemslistView);
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
Bundle itemintent = getActivity().getIntent().getExtras();
String ItemName = itemintent.getString("ListItemName");
if (ItemName.equals("ItemName")) {
/** Items entered by the user is stored in this ArrayList variable */
ArrayList<String> list = new ArrayList<String>();
list.add(ItemName);
/** Declaring an ArrayAdapter to set items to ListView */
ArrayAdapter<String> Listadapter;
Listadapter = new ArrayAdapter<String>(getActivity().getApplicationContext(),android.R.layout.simple_list_item_1, list);
lv.setAdapter(Listadapter);
Listadapter.notifyDataSetChanged();// i don't think this line is necessary
}
return rootView;
}
The better way to do this is as below:
Start main activity
give a button to add item
on click of this button, call the activity(use startActivityForResult ) having edittext and a button
and on this button click, setResult with intent extras and finish this activity.
it will to MainActivity. Here write your onActivityResult method and handle it based on the result code. get your data from intent here.
Hope this answer helps you.
Hy, i've got list view in my fragment. I am replacing this listview fragment with my other fragment but when i want back to my list, it's empty. I thought i could restore my list items but i don't know how. I Assumed that accord with Fragment lifecycle my adapter will be reusable but looks it's not. Here is my code:
public class ThreadListFragment extends Fragment implements FragmentConnectionStatus, ListFragment, OnClickListener, OnItemClickListener{
private ListView ListView;
private PilotController Activity;
private Button ButtonStartNewThread;
private boolean Paused;
private ThreadInfoAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
/**
* Inflate the layout for this fragment
*/
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.threads_list_fragment, container, false);
System.out.println(this.Paused);
if(this.Paused == false){
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
this.ListView.setAdapter(adapter);
this.ListView.setItemsCanFocus(true);
this.ListView.setOnItemClickListener(this);
this.Activity = (PilotController) getActivity();
this.ButtonStartNewThread = (Button) view.findViewById(R.id.buttonStartThread);
this.ButtonStartNewThread.setOnClickListener(this);
return view;
}
#Override
public void onPause()
{
super.onPause();
this.Paused = true;
}
but when i return to my old list, it's empty. Could you give me some advice?
SOLUTION
I found a solution. ListView is probably removing from 'draw stack' so when calling OnDeleteView your old list is unusable next time although reference to this object is still set. The solution is to recreate ListView and set old adapter. This adapter due to this tutorial http://developer.android.com/guide/components/fragments.html will survive but view is recreated (so old listview doesn't exist anymore (it exist but it's not drawable). I had to change this lines:
if(this.Paused == false){
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
to:
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
if(this.Paused == false){
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
In "onActivityCreated" you can just check if your dataList (in your case "strs) is empty. If it is not then just use it, otherwise create a new one. In code it would look like this:
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (strs == null)
strs = new ArrayList<Guid>();
mListView = (ListView)getActivity().findViewById(R.id.listViewActiveThreads);
mPersonAdapter = new ArrayAdapterPerson(getActivity(),mPersonList,this);
mListView.setAdapter(mPersonAdapter);
}
I found my solution here: ListFragment is empty after going back
use transaction.hide(this):
ft.addToBackStack(null);
ft.hide(this);
ft.add(R.id.frag_frame, lyrics);
ft.commit();
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);
Confused as to why the onClickListener is not responding. Is it because but buttons are set in one layout, but bound to another one? Any help would be appreciated.
public class ActivityList extends ListFragment
{
private ActivityDbAdapter mDbHelper;
private Long mRowId=Long.valueOf(1);
private Activity mContext; //changed to private
AlertDialog activity_relationship;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mContext=this.getActivity();
mDbHelper=new ActivityDbAdapter(mContext);
mDbHelper.open();
Cursor activity = mDbHelper.fetchAll(mRowId);
View view = (View) inflater.inflate(R.layout.activity_activity_row, container,false);
Button relationship = (Button) view.findViewById(R.id.show_relationship_activities);
String[] from = new String[]{ActivityDbAdapter.COLUMN_NAME_VALUE1_RELATIONSHIP , //from and too.
ActivityDbAdapter.COLUMN_NAME_VALUE1_EDUCATION,
ActivityDbAdapter.COLUMN_NAME_VALUE1_RECREATION,
ActivityDbAdapter.COLUMN_NAME_VALUE1_MIND, ActivityDbAdapter.COLUMN_NAME_VALUE1_DAILY};
int[] to = new int[]{R.id.relationship_value,R.id.education_value, R.id.recreation_value,
R.id.mind_value, R.id.daily_value};
SimpleCursorAdapter contacts =
new SimpleCursorAdapter(mContext, R.layout.activity_activity_row, activity, from, to); //my cursor adapter
relationship.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg) {
Log.e("Why","Are you not working?");
Cursor activity = mDbHelper.fetchAll(mRowId);
String mactivity_relationship=activity.getString( //define all of the Strings. Gahh!!
activity.getColumnIndexOrThrow(ActivityDbAdapter.COLUMN_NAME_ACTIVITY1_RELATIONSHIP));
AlertDialog activity_relationship=new AlertDialog.Builder(mContext).create();
activity_relationship.setTitle("Relationship Activities");
String activities=(mactivity_relationship+"\n"+mactivity_relationship2+"\n"+mactivity_relationship3+
"\n"+mactivity_relationship4+"\n"+mactivity_relationship5);
activity_relationship.setMessage(activities);
activity_relationship.show();
}
});
setListAdapter(contacts);
return inflater.inflate(R.layout.activity_activity_list, container, false);
}
}
As I have it right now, the log is not even showing up.
You may want to return the view that you actually create(and use for getting the Button) in the onCreateView:
//...
return view;
instead of returning a newly inflated layout(and losing the previous Button):
return inflater.inflate(R.layout.activity_activity_list, container, false);
Or add the view to a view from the R.layout.activity_activity_list file that you inflate and return.