From the title it might be a little unclear what I want to ask so allow me to explain.
In my project, I need to make a dynamic view in a while loop. Like so;
private void loadCheckPointQuantity() {
final LinearLayout rgLayoutContainer = (LinearLayout)findViewById(R.id.quantityAnswers);
_answerCursor.moveToFirst();
while(_answerCursor.isAfterLast() == false) {
LinearLayout rgContainer = new LinearLayout(this);
rgContainer.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
rgContainer.setOrientation(LinearLayout.HORIZONTAL);
final ImageView checked = new ImageView(this);
checked.setMinimumHeight(30);
checked.setMinimumWidth(30);
if(_answerCursor.getInt(CPA_IS_CHECKED_COL) == 1) {
checked.setBackgroundResource(R.drawable.btn_check_buttonless_on);
} else {
checked.setBackgroundResource(R.drawable.ic_delete);
}
checked.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
TextView txtAmount = new TextView(this);
txtAmount.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
txtAmount.setText((_answerCursor.getPosition() + 1) + "/" + _answerCursor.getCount());
txtAmount.setTextSize(22);
RadioGroup rgAnswer = new RadioGroup(this);
rgAnswer.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
rgAnswer.setOrientation(RadioGroup.HORIZONTAL);
rgAnswer.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch(checkedId) {
case 0:
checked.setBackgroundResource(R.drawable.ic_delete);
break;
case 1:
checked.setBackgroundResource(R.drawable.btn_check_buttonless_on);
break;
}
}
});
RadioButton rbYes = new RadioButton(this);
rbYes.setText(R.string.yes);
rbYes.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
rbYes.setId(1);
RadioButton rbNo = new RadioButton(this);
rbNo.setText(R.string.no);
rbNo.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
rbNo.setId(0);
ImageButton camButton = new ImageButton(this);
camButton.setImageResource(R.drawable.ic_menu_camera);
camButton.setLayoutParams(new LayoutParams(70, 70));
final EditText txtNote = new EditText(this);
txtNote.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
txtNote.setEnabled(false);
txtNote.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean hasFocus) {
if(!hasFocus) {
txtNote.setSingleLine(true);
} else {
txtNote.setSingleLine(false);
}
}
});
rgAnswer.addView(rbYes);
rgAnswer.addView(rbNo);
rgContainer.addView(checked);
rgContainer.addView(txtAmount);
rgContainer.addView(rgAnswer);
rgContainer.addView(camButton);
rgContainer.addView(txtNote);
rgLayoutContainer.addView(rgContainer);
if(_answerCursor.getInt(CPA_ANSWER_COL) == 1) {
rbYes.setChecked(true);
} else if(_answerCursor.getInt(CPA_ANSWER_COL) == 0) {
rbNo.setChecked(true);
}
if(_answerCursor.getInt(CPA_ANSWER_COL) == 0 || _answerCursor.getInt(CPA_ANSWER_COL) == 1) {
txtNote.setEnabled(true);
}
_answerCursor.moveToNext();
}
_answerCursor.moveToFirst();
}
What happens is, There is a field in the databasethat determines how many times the loop should be crossed. A quantity. So if quantity is 5. The components should be made 5 times.
The problem is,
Because I do all that in a method, I can't access the individual views.
For example, and this is what needs to happen in reality as well;
I click a button. Then I need to save all results in the database.
Ie for the EditText's and isChecked's radiogroup results.
The problem is, I don't know how I can access each individual view.
I have thought of several things to solve this. But they all end up creating question marks above my head
I tried, making a class to represent an answer(isChecked, note, etc(with getters and setters)
create an array list, put them all in an arraylist.
this should work. Putting the answers in an arraylist. But that leaves me with the next problem. What i a text changes? How can I handle this?
if I use observables, should I make the answer class observable, should I call setChanges() for every member, and implement observable in the class containing the loadCheckPointQuantity?
I have exactly 0,4 experience with observables.
How would I go about saving the latest data when pressing the next button?
I am absolutely clueless...
Since it might be vague:
What I try to achieve: Save the latest data from all views to the database
how: help needed
when: on button click
The time you took to understand/look at/read this post is highly appreciated. Answers even more highly.
If you need more code or explanation. Let me know and I will do my best.
I solved my issue.
I assigned eventlisteners to all things that need to eventuall end up in a database.
On focus change, I save the data to the database. So I don't hold any lists whatsoever holding answers. I update the database on the fly. Unfortunately, it is bad for performance. Fortunately, we can afford this performance.
I tried to run this code telling the while loop to execute it 3000 times. Apart from the view generation taking some time(about 3-4seconds on average), all ran fine. So I don't need to keep track of the generated objects outside of the method. android/java does that for me.
Related
I create a vertical list of textviews with an arraylist and attach on onclicklistener to each one. In the onclick I set code to remove that item. When I click in sequence from the last generated to the first this works fine. But if I remove the first one and then the last one it gives me a null pointer exception. I know this is happening because it is attempting to remove an index that is no longer present, or at least that is what I think is happening. But I cannot figure out how to solve that.
private void generateViews(){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
final TextView[] textView = new TextView[questionArray.size()];
for(int i = 0; i < questionArray.size(); i++){
final int Index = i;
textView[Index] = new TextView(getActivity());
textView[Index].setText(questionArray.get(i));
textView[Index].setId(Index);
textView[Index].setGravity(Gravity.CENTER);
textView[Index].setPadding(15,15,15,15);
textView[Index].setLayoutParams(params);
textView[i].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (textView[Index].getId() == (v).getId()) {
questionArray.remove(Index);
answerArray.remove(Index);
saveVariables();
updateViews();
((ViewGroup) textView[Index].getParent()).removeView(textView[Index]);
Toast.makeText(getActivity(), "Question and Answer removed!", Toast.LENGTH_SHORT).show();
}
}
});
mainLayout.addView(textView[Index]);
}
EDIT:
I figured out a small fix but it has it's problems. Instead of removing the items from the arrays with the index I can remove them by searching for the text within the textview.
The problem with this solve is that if my array contains 2 items that are identical then it may remove the wrong index.
questionText = textView[Index].getText().toString();
answerText = textView[Index].getText().toString();
if(questionArray.contains(questionText) && questionArray.size() > 0){
questionArray.remove(questionText);
answerArray.remove(answerText);
}
Solved:
I solved it by first searching for the index of the question text and removing that index from both arrays. The arrays are user generated and I plan on preventing the user from entering the same question twice.
questionText = textView[Index].getText().toString();
int questionIndex = questionArray.indexOf(questionText);
questionArray.remove(questionIndex);
answerArray.remove(questionIndex);
Also, I did it this way because I am still an amateur and was not aware of the Recyclerview. I plan on educating myself on that function and hopefully implementing it.
I really have no idea about why you want do this? if you just want remove textview in a list , why don't you use listview or recyclerview instead ?
You should consider using RecyclerView.
I have been on this problem for a while now.
I am hoping to gather top trending keywords and place into an ArrayList.
Each keyword is to be placed on a toggleButton, (user selects keyword and it enhances search). I need the buttons to be in a grid like form on the Android mobile app, I also need the buttons to be placed in an ArrayList so I can reference later. I've tried so many different loops, for loops and loops in loop and keep hitting the same two problems:
prob 1) either the keywords are not read, or repeated in each column if I create the buttons within the layout loop.
prob 2) I create the buttons first and then reference to them in the layout loop and I get a error message:
"java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first"
I've scanned the internet, I've tried different methods and I think its just something I am missing in my code (this layer of code is one of many layers, this one holds the buttons...any pointers will be appreciated.
trending = new ArrayList<String>() {
{
add("one"); add("two"); add("three") ;add("four");add("five");
add("six");add("seven");add("eight");add("nine");add("ten");
add("eleven");
}};
//LAYOUT SETTINGS 5
TableLayout rLayout5 = new TableLayout(this);
rLayout5.setOrientation(TableLayout.VERTICAL);
LayoutParams param7 = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
param7.addRule(RelativeLayout.BELOW, rLayout4.getId());
rLayout5.setBackgroundColor(Color.parseColor("#EEEBAA"));
rLayout5.setLayoutParams(param7);
// List<ToggleButton> togButtStore = new ArrayList<ToggleButton>();
int i = 0 ;
while (i < trending.size()){
if (i % 3 == 0){
tr = new TableRow(this);
rLayout5.addView(tr);
}
toggBtn = new ToggleButton(this);
toggBtn.setText(trending.get(i));
toggBtn.setId(i);
toggBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//something here
}
});
tr.addView(toggBtn);
i++;
}
rLayout5.addView(tr); ///<---error points to this line
root.addView(rLayout1);
rLayout1.addView(text1);
root.addView(rLayout4);
root.addView(rLayout3);
root.addView(rLayout5);
setContentView(root);
}
You are adding tr twice to the rLayout5. Delete the line where your error is....
Im a bit stuck on the best way to implement this so here I am.
I have a list of shared preferences with a label and a price. My app, a sort of calculator if you will, I would like to load the shared preferences in this way but stuck on how to implement it properly so ill wrote it down in a very literal way
Load shared preferences "item1"
Load into textView1 if empty
if it is full then try textview2,
if it is full then try textview3,
etc etc
I would like a function which loads preference 1, attempts to load it into a view and if its full, try the next textview and so on until it finds and empty slot. and then try the next shared preference item
Maybe I'm looking at this wrong but without writing out tons of if/else statements to get the job done, I cant see a way that makes sense.
I've seen somewhere some code to increment the textview numbers in a loop until a case is met but cant seem to recall it anywhere. this would reduce the code a lot if this was implemented properly I'm sure.The app I'm creating will display a list of selected items from another screen,save selected to shared preferences and then load the list on the results screen to give a total based on the sums attached to the items loaded.
I have no actual code to give you as im still prototyping this section and have nothing solid to show you.
any pointers welcome or any nod in the right direction would be handy.
thanks guys
You could add TextViews dynamiclly through java.
public class DynamicAvtivity1 extends Activity {
TextView tv;
EditText et;
Button btn;
LinearLayout ll;
int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
i = 1;
ll = new LinearLayout(this);
ll.setOrientation(1);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT , LayoutParams.FILL_PARENT);
final LinearLayout.LayoutParams lp2 = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT , LayoutParams.WRAP_CONTENT);
ll.setLayoutParams(lp);
tv = new TextView(this);
tv.setText("Enter Name");
tv.setLayoutParams(lp2);
ll.addView(tv);
et = new EditText(this);
et.setHint("Name");
et.setLayoutParams(lp2);
ll.addView(et);
btn = new Button(this);
btn.setLayoutParams(lp2);
btn.setText("Add Button");
btn.setLayoutParams(lp2);
ll.addView(btn);
btn.setOnClickListener(new View.OnClickListener() {
#SuppressLint("NewApi") #Override
public void onClick(View v) {
// TODO Auto-generated method stub
Button b = new Button(getApplicationContext());
b.setLayoutParams(lp2);
b.setText("Button " + i++);
b.setTextColor(Color.BLACK);
b.setBackground(btn.getBackground());
ll.addView(b);
}
});
setContentView(ll);
}
}
First off I have searched for this info for about a week and found very little. So hopefully this long read helps some other new people.
I have created a UI from JSON. This UI has all kinds of Views. Such as EditText, RadioButton, CheckBox, Spinner, etc. Now I need to account for certain inevitable scenarios. Screen rotation, phone call, back button, home button etc. Since all these Views are created after a network call/response and this takes time I do not want to repeat this action each time. So saving the actual RadioButton or EditText and what was selected on the RadioButton or typed into the EditText is extremely important. From what I've read for screen rotation I use onSaveInstanceState(). For anything else I would use onPause() because it is the only thing that is garunteed to be called.
The problem is I have no idea how to store programatically created Views with no id's in sharedprefs or a bundle let alone the values they hold. Lets look at my code and then discuss what I think is currently possible.
allEdit = new ArrayList<EditText>();
else if (map.get(TAG_FIELD).equals(et)) {
Log.v("RESPONSE", "About to create an EditText");
// find
LinearLayout content = (LinearLayout) getActivity()
.findViewById(R.id.add);
// create
TextView tv = new TextView(getActivity());
EditText et = new EditText(getActivity());
LinearLayout ll1 = new LinearLayout(getActivity());
// set
tv.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT));
et.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
ll1.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
tv.setText(map.get(TAG_NAME));
ll1.setOrientation(LinearLayout.HORIZONTAL);
// add
ll1.addView(tv);
ll1.addView(et);
allEdit.add(et);
content.addView(ll1);
}
So in the example above I have created an EditText and stored it in an ArrayList<EditText>. Now my thought is that in onPause() I could do something like this.
for (int i = 0; i < allEdit.size(); i++) {
EditText et = allEdit.get(i);
String input = et.getText().toString();
prefsEdit.put(input);
}
Which I think might work, it also might overwrite the String "input" inside shared preferences over and over again. Not totally sure how that works. It also still does not solve how to save the actual EditText so that it does not have to be recreated.
Now in onSavedInstanceState() I think I may be able to get away with just inserting the whole ArrayList<EditText> as serializable, right? Like this...
putSerializable("key", allEdit)
However that does not save the values inside them.
So how do I save these Views and their values in onSavedInstanceState() and onPause()? Perhaps more importantly, do I need both? Can I get away with just using onPause()?
Thank you
I havent tried this, but it sounds like it would work in practice. When creating the activity (before the JSON populates) create your own ViewGroup. From there, read the JSON and add every view that you get to the VeiwGroup. Then, when you want to save the information or whatever do this
int viewCount = mViewGroup.getChildCount();
for(i=0;i<viewCount;i++) {
newView = mViewGroup.getChildAt(i);
if (newView instanceOf EditText) {
EditText newEditText = (EditText)newView
string value = newEditText.getText();
}
else if (newView instanceOf RadioButton) {
same as above ^
etc...
}
}
Then, for each of the values you pull add them to an array, maybe even a NamedPair to store their ID and value (by ID I mean index of which view it is). So
public List<String> lstEditTextValues = new ArrayList<String>();
After all that is said and done, then you can itterate through each one, and save it as an individual value through the bundle, save in a shared pref, or put into a static class level variable (not the safest way to retain information, but does work).
Hope this helps. Let me know if im completely off topic
In my application I create dynamic rows in table much as in this tutorial:
http://en.androidwiki.com/wiki/Dynamically_adding_rows_to_TableLayout
for(int i = startDay; i < startDay + 7; i++){
/* Create a TextView to be the row-content. */
TextView day = new TextView(this);
day.setText(Integer.toString(i));
day.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
day.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Listener: ", "Click");
}
So now when I click on a TextView I can register click event, but how do I determine which TextView was clicked?
Not just an object which I get with an event but data like which day number was clicked?
Ideally I would want to have data attached to every view I create dynamically.
Something like data() method in Javascript jQuery.
Right now I can see only 1 way to solve this - while creating TextView add id with data and when clicked - get id back and parse it to get my data. But it strikes me as ugly approach.
Is there a way to attach arbitrary data to android views?
Found answer going through view methods. Maybe it will be useful for someone.
Methods I needed were:
setTag() and getTag()
http://developer.android.com/reference/android/view/View.html#setTag%28java.lang.Object%29