I am confused about calling the spinner widget through a custom function. I am create an app in which I use spinner 20-35 times a spinner widget in single layout or activity. So for this i want to avoid the spinner code repetition again and again. i am creating a method for this i add the items to the spinner but i want to pass item value on select to other activity which bind to that class
Here is my code
Spin_tester.class
public class Spin_tester {
public String result;
public Context ctx;
public Spin_tester(Spinner spinner, final ArrayList<String> arraylist, final Context ctx , final String value) {
this.ctx= ctx;
ArrayAdapter<String> adpts =
new ArrayAdapter<String>(ctx, android.R.layout.simple_dropdown_item_1line,arraylist);
spinner.setAdapter(adpts);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
result = arraylist.get(position);
value = result ; // This is not working
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
}
Test_Activity.class
public class Test_Activity extends AppCompatActivity {
ArrayList<String> data_list = new ArrayList<>();
Spinner spins;
String value;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
spins = (Spinner)findViewById(R.id.spinner);
data_list.add("1");
data_list.add("2");
data_list.add("3");
data_list.add("4");
Spin_tester asd = new Spin_tester(spins,data_list,this,value);
TextView txt = (TextView)findViewById(R.id.textView17);
}
}
Please help
Thanks in advance
Java is a pass-by-value language, not pass-by-reference. What this means is that setting value in setOnItemSelectedListener will only change value within that method — the result won't be passed back anywhere.
I see that you've place the result in result. That is where the calling program will find the answer.
Remove all instances of value from Spin_tester and Test_Activity and then have your main activity get the result from asd.result
I'm going to get a little meta at this point: I've only answered the question you actually asked, but this code is wrong on so many levels that you're never going to get it to work. I strongly suggest you work your way through the examples and tutorials in the documentation before you try to proceed any further.
Related
this is my first post here so be gentle :p
Here is the thing, I'm facing a really though issue and after several research i did not manage to figure out a clean solution. Let me explain:
I'm actually developing an android app for restaurant management.
In activity A, i'm able to create some articles with different parameters (picture, name, price ..).
I can also create a menu in which i indicate which articles are included. To do so i run Activity B that contains a dynamic list of the available articles (the ones i created) to be chosen. After picking up some of them the customised chosen objects are sent to Activity A through Parcel. And the chosen article list is updated in the menu.
But here is the thing, as far as i know, using Parcels create another instance of the object. As a result, if i modify or delete an article, the article list included in the menu does not change, and obviously i would like the list in the menu to be automatically updated.
Is there a way to simply pass customised objects through activities by reference?
What could be a clean solution to make the article list in the menu dynamic?
Here is some code:
In Activity A, in the menu interface i click + button to add an article, which run Activity B (the extras is the list of articles already included in the menu before, so in the beginning it's empty).
//Add article
FloatingActionButton addArticleButton = (FloatingActionButton)parentActivity.findViewById(R.id.addArticleButton);
addArticleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showMenuDetails(menuListView,menuAdapter,currentMenu);
parentActivity.startActivityForResult(new Intent(parentActivity.getApplicationContext(),ChooseArticleActivity.class).putParcelableArrayListExtra("menuArticleList",currentMenu.getArticles()),PICK_ARTICLES);
}
});
In activity B: I select Articles in a list of available Articles (the ones i created). After picking up i press OK button to put the list of chosen articles in result Intent as Parcelable Extras
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_article_layout);
initializeLists();
this.resultIntent = new Intent();
}
private void initializeLists(){
final ListView articleToChoose = (ListView)findViewById(R.id.articleToChoose);
final ListView articleChosen = (ListView)findViewById(R.id.articleChosen);
final ArrayList<Article> articleToChooseList = (ArrayList<Article>)MainActivity.model.getArticleList().getArticleList().clone();
final ArrayList<Parcelable> articleChosenListParcelable = (ArrayList<Parcelable>)this.getIntent().getParcelableArrayListExtra("menuArticleList");
final ArticleAdapter articleToChooseAdapter = new ArticleAdapter(getApplicationContext(), articleToChooseList);
articleToChoose.setAdapter(articleToChooseAdapter);
ArrayList<Article> articleChosenListTemp = new ArrayList<>();
ArrayList<Article> articleToRemove = new ArrayList<>();
for(Parcelable a:articleChosenListParcelable){
articleChosenListTemp.add((Article)a);
for(Article article:articleToChooseList){
if(article.getName().equals(((Article) a).getName())){
articleToRemove.add(article);
}
}
}
articleToChooseList.removeAll(articleToRemove);
articleToChooseAdapter.notifyDataSetChanged();
final ArrayList<Article> articleChosenList = articleChosenListTemp;
final ArticleAdapter articleChosenAdapter = new ArticleAdapter(getApplicationContext(),articleChosenList);
articleChosen.setAdapter(articleChosenAdapter);
articleChosen.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Article articleClicked = articleChosenAdapter.getItem(position);
articleChosenList.remove(articleClicked);
articleToChooseList.add(articleClicked);
articleChosenAdapter.notifyDataSetChanged();
articleToChooseAdapter.notifyDataSetChanged();
}
});
articleToChoose.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Article articleClicked = articleToChooseAdapter.getItem(position);
if(!articleChosenList.contains(articleClicked)){
articleChosenList.add(articleClicked);
articleToChooseList.remove(articleClicked);
articleToChooseAdapter.notifyDataSetChanged();
articleChosenAdapter.notifyDataSetChanged();
}
}
});
Button okButton = (Button)findViewById(R.id.okButton);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chosenArticleListAttr = articleChosenList;
resultIntent.putParcelableArrayListExtra("articleList",chosenArticleListAttr);
setResult(RESULT_OK,resultIntent);
finish();
}
});
Button cancelButton = (Button)findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
In activity A, in onActivityResult i catch the result and update the list, but the added Articles here are not the same instance as the article list in the model
if(requestCode==PICK_ARTICLES && resultCode==RESULT_OK){
ArticleAdapter articleAdapter = (ArticleAdapter) gestionMenusLayout.getMenuArticleListView().getAdapter();
ArrayList<Parcelable> chosenArticleList = (ArrayList<Parcelable>)data.getParcelableArrayListExtra("articleList");
gestionMenusLayout.getCurrentMenu().getArticles().clear();
for(Parcelable a:chosenArticleList){
gestionMenusLayout.getCurrentMenu().addArticle((Article)a);
}
articleAdapter.notifyDataSetChanged();
}
For debugging purpose only, I suggest that you use a public static List<Article> articleList and call it directly from whether activity A or B
A better but take-alittle-more-effort solution is that you store the list in a database, and every updates, queries, ... come through it.You can use the server's database (where people usually get articles from), or a offline database like Realm here
I figured it out with a quite easy and simple solution finally.
I keep passing my Article objects through intents by parcels.
But as it creates a new instance, instead of adding this instance i add the original one (the one from the model) after an equality key check (the name of the article). By doing so i keep the reference on my Article.
Thank you for helping!
Edit:
Here is the code:
if(requestCode==PICK_ARTICLES && resultCode==RESULT_OK){
ArticleAdapter articleAdapter = (ArticleAdapter) gestionMenusLayout.getMenuArticleListView().getAdapter();
ArrayList<Parcelable> chosenArticleList = (ArrayList<Parcelable>)data.getParcelableArrayListExtra("articleList");
gestionMenusLayout.getCurrentMenu().getArticles().clear();
ArrayList<Article> modelArticles = MainActivity.model.getArticleList().getArticleList();
for(Parcelable a:chosenArticleList){
for(Article modelArticle:modelArticles){
if(((Article)a).getName().equals(modelArticle.getName())){
gestionMenusLayout.getCurrentMenu().addArticle(modelArticle);
}
}
}
articleAdapter.notifyDataSetChanged();
}
I found error in findViewById in static function.
my function is--
public static void onYearSelect() {
Spinner yearSelector;
String yearName;
yearSelector = (Spinner) findViewById(R.id.year_submit);
yearName = yearSelector.getSelectedItem().toString();
}
is there any way to solve this error!
can i store value of Spinner in yearName as String
You need to add view inside function as parameter.
public static void onYearSelect(View view) {
Spinner yearSelector;
yearSelector = (Spinner) view.findViewById(R.id.year_submit);
yearName = yearSelector.getSelectedItem().toString();
}
The view which contains your layout data.
When you call that function add onYearSelect(rootView) here rootView have the layout view.
EDIT 1:
What is View here ?
A View in Android is a widget that displays something. Buttons, listviews, imageviews, etc. are all subclasses of View. When you say "change view" I assume you mean change the layout by using setContentView(). This usually only needs to be done once per activity. An Activity is basically what you are referring to as a screen.
You can read more here.
Set setOnItemSelectedListener on spinner object and inside onItemSelected() you can set value of yearName. Like below,
yearSelector.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
String yearName = parentView.getItemAtPosition(position).toString()
}
#Override
public void onNothingSelected(AdapterView<?> parentView) {
// your code here
}});
I'm new to android development, I have some experiences on C# windows programming, but also very little. I'm working on an android application which uses spinners. So far, I found a tutorial which make spinner items, and displays spinner text in text view, as you select spinner item. The code lookes like this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
spinner =(Spinner)findViewById(R.id.sp);
text=(TextView)findViewById(R.id.tv);
ArrayAdapter<CharSequence> adapter =ArrayAdapter.createFromResource(this, R.array.spinnerarray, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new function());
}
public class function implements OnItemSelectedListener {
#Override
public void onItemSelected(AdapterView<?> parent, View arg1, int pos,
long id) {
// TODO Auto-generated method stub
String str=parent.getItemAtPosition(pos).toString();
text.setText(str);
}
I want to make an application, which will calculate some points, with the grade user would choose. Example: spinner will contain grades, such as Negative(1), Positive(2),Good(3), Very Good(4), Excellent(5). I want to achieve, that when an user chooses one grade, lets say very good, that the application will use the grade for very good which is 4, and it would transform it to some points, determined by me ( 1=20, 2=40,3=60,4=80,5=100). The points will be later used in calculation, but I have no idea how to assign points to certain grade. I hope you understand my question and thank you for your help.
I had the same app for windows, there I just used something like: if(veryGood.IsSelected==true){points = 20}, and i want to achieve same effect here.
You need a simple modifications on your function class:
public class function implements OnItemSelectedListener {
private final static int[] grades = new int[]{20,40,60,80,100}; //change in whatever you want. The length of the array must be the same of the adapter, or an ArrayIndexOutOfBoundException may be throwed.
#Override
public void onItemSelected(AdapterView<?> parent, View arg1, int pos, long id) {
text.setText(grades[pos] + " points!");
}
}
PS: in Java is a good practice to use upper case initial on class names e.g. Function instead of function.
I wrote a code for Spinner to bind array of USA States with Spinner in Android. But the problem is it shows reference type data in Spinner item, see the pic
I add android.R.layout.simple_spinner_dropdown_item but not know that what to add in layout. I checked many exemples on google and they add simple_spinner_dropdown_item but i could not find that what to add in layout. below is output and code. I want to show states in list instead of this junky data.
Spinner spStates = new Spinner(this);
spStates.setLayoutParams(new LayoutParams(screenWidth, LayoutParams.WRAP_CONTENT));
final USAStates states[] = new USAStates[51];
states[0] = new USAStates("Alabama", "AL");
states[1] = new USAStates("Alaska", "AK");
states[2] = new USAStates("Arizona", "AZ");
ArrayAdapter<USAStates> adapter = new ArrayAdapter<USAStates>(this, android.R.layout.simple_spinner_item, states);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spStates.setAdapter(adapter);
spStates.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
USAStates d = states[position];
Toast.makeText(getApplicationContext(), d.getStateAbrivation(), Toast.LENGTH_LONG).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
public class USAStates {
private String _Statename;
private String _StateAbrivation;
public USAStates(String pStatename, String pStateAbrivation) {
Statename(pStatename);
StateAbrivation(pStateAbrivation);
}
public void Statename(String pStatename) {
_Statename = pStatename;
}
public void StateAbrivation(String pStateAbrivation) {
_StateAbrivation = pStateAbrivation;
}
public String getStatename() {
return _Statename;
}
public String getStateAbrivation() {
return _StateAbrivation;
}
}
Not sure, just doing this off the top of my head but, in your USAState class override your toString method.As is it maybe that the adapter is using the default toString() hence your weird text displaying (which I presume is the class name of the USAStates class)
for example
#Override
public String toString(){
return _Statename
}
I originally accepted the toString() answer but have since found that this doesn't appear to be right.
I had an ActionBar with spinner/drop down list and my adapter items were rendering with String.toString() value instead of of the title I set in the custom adapter. Adding toString() did fix initially until I tried to set a compound drawable in the same layout.
I needed to override getDropDownView as well as getViewin my adapter.
Having to override toString() is symptomatic that you haven't overridden the right methods in your adapter.
When overriding getDropDownView having to override toString() is no longer required and everything works as expected.
And the answer on the following post is a great way to implement by using the super method:
alternating colors of spinner items
OK, I've read around and see that Java only passes by value, not by reference so I don't know how to accomplish this.
I've 6 Spinners in an Android Activity that are populated with different SQLite queries.
The code to populate each Spinner and set the OnItemSelectedListener is very similiar so I was hoping to refactor to one method and call it 6 times with each Spinner ID and Sqlite query.
How do I get the Spinner onItemSelectedListener to change the right instance member on each different Spinner?
public void fillSpinner(String spinner_name, final String field_name) {
// This finds the Spinner ID passed into the method with spinner_name
// from the Resources file. e.g. spinner1
int resID = getResources().getIdentifier(spinner_name, "id",
getPackageName());
Spinner s = (Spinner) findViewById(resID);
final Cursor cMonth;
// This gets the data to populate the spinner, e.g. if field_name was
// strength = SELECT _id, strength FROM cigars GROUP BY strength
cMonth = dbHelper.fetchSpinnerFilters(field_name);
startManagingCursor(cMonth);
String[] from = new String[] { field_name };
int[] to = new int[] { android.R.id.text1 };
SimpleCursorAdapter months = new SimpleCursorAdapter(this,
android.R.layout.simple_spinner_item, cMonth, from, to);
months.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(months);
// This is setting the Spinner Item Selected Listener Callback, where
// all the problems happen
s.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
Cursor theCursor = (Cursor) parent.getSelectedItem();
// This is the problem area.
object_reference_to_clas_member_of_field_name = theCursor
.getString(theCursor.getColumnIndex(field_name));
}
public void onNothingSelected(AdapterView<?> parent) {
// showToast("Spinner1: unselected");
}
});
}
You call this method like this fillSpinner("spinner1","strength");.
It finds the spinner with id spinner1 and queries the database for the strength field. field_name, which is strength in this example had to be declared a final variable to be used in the onItemSelectedListener or I'd get the error Cannot refer to a non-final variable field_name inside an inner class defined in a different method.
But how do I get the onItemSelectedListener to change the value of a different instance member when each different Spinner is used? This is the all important line of code:
object_reference_to_clas_member_of_field_name = theCursor .getString(theCursor.getColumnIndex(field_name));
I can't use a final String as the variable will obviously change when the user selects a different value. I've read around a good bit and am stumped to a solution. I can just copy and paste this code 6 times and forget about refactoring but I'd really like to know the elegant solution. Post a comment if you don't understand my question, I'm not sure if I explaned myself well.
You can do it, by passing additional class as parameter of fillSpinner method:
A. Create interface
public interface OnSpinnerValueSelected {
void onValueSelected(String selectedValue);
}
B. Change your method a bit:
public void fillSpinner(String spinner_name, final String field_name,
final OnSpinnerValueSelected valueChangeListener) {
// Prepare spinner
s.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
Cursor theCursor = (Cursor) parent.getSelectedItem();
valueChangeListener.onValueSelected(theCursor
.getString(theCursor.getColumnIndex(field_name)));
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
C. provide listener:
fillSpinner("spinner1","strength", new OnSpinnerValueSelected() {
public void onValueSelected(String selectedValue) {
yourObject.setField(selectedValue);
}
});
Refactor your listener to a new "class". Initialize with the right arguments/instances as required so that the repeated "code" is reusuable.
Right, this is how I managed it but I'm still open to new suggestions for an accepted answer and I also created a bounty.
I didn't create a new class like panzerschreck suggested so I'm posting this as a new answer to my own question. Bit of a hack but I just created an if..then..else statement in the listener to check what spinner was selected and then set a different instance member.
s.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
Cursor theCursor = (Cursor) parent.getSelectedItem();
if (field_name.equalsIgnoreCase("strength")) {
strength=theCursor.getString(theCursor.getColumnIndex(field_name));
} else if (field_name.equalsIgnoreCase("ring")) {
ring_gauge=theCursor.getString(theCursor.getColumnIndex(field_name));
} else if (field_name.equalsIgnoreCase("country")) {
country=theCursor.getString(theCursor.getColumnIndex(field_name));
} else if (field_name.equalsIgnoreCase("wrapper")) {
wrapper=theCursor.getString(theCursor.getColumnIndex(field_name));
} else if (field_name.equalsIgnoreCase("length")) {
length=theCursor.getString(theCursor.getColumnIndex(field_name));
} else if (field_name.equalsIgnoreCase("price")) {
price=theCursor.getString(theCursor.getColumnIndex(field_name));
}
// showToast(category);
}
public void onNothingSelected(AdapterView<?> parent) {
// showToast("Spinner2: unselected");
}
});
Here are the class members
private String strength,ring_gauge,country,wrapper,length,price;
Bit of hack but without Java allowing objects to be really passed by reference, it's all I could do.