When I select one of the items from the listview that is not visible when the activity is created it throws an exception becuase those that are not visible are null. As you see, I already know why the problem gives the exception and I would thank the one that gives me the tip for solving it. Here's the code.
public void myFunction(View view) {
int i, i2 = 0;
// get the row the clicked button is in
ListView lerroa = (ListView) view.getParent();
i = lerroa.getPositionForView(view);
System.out.println(i + 1);
LinearLayout ll = (LinearLayout) lerroa.getChildAt(i);
TextView pedido = (TextView) ll.getChildAt(0);
}
Any easier way of taking the textview at the item that has been clicked on?
I've solved the problem.
In order to show also the items of the list view that were not visible, those that caused the NullPointers, I've replaced the line of code which crashed the app. Here it is:
Replace:
LinearLayout ll = (LinearLayout) lerroa.getChildAt(i);
For this one:
LinearLayout ll = (LinearLayout) lerroa.getChildAt(i -lerroa.getFirstVisiblePosition()).findViewById(R.id.LinearLayout3);
getVisiblePosition allows us playing with the first item shown at the LinearLayout and so avoids any NullPointer.
I know this is a bit shoddy and that is not the best way to code what I want to achieve. In spite of this, I've seen so many times the same error on the internet but without any correct answare. I wish this would be usefull for others.
Have a nice code!
Related
I am adding a layout on a Button click that layout contains a TextView and the 2 Spinners name spGrades and spMarks.
User can add multiple layout. So all I want is to get the value of Spinners on the TextView click . well I am getting of values of Spinner but I am facing following problems.
In Case1: Suppose there is just one layout added by the user let say
Student1MarksLayout then on the click of the TextView I am getting
the values of Spinners.
In Case 2: Suppose now user has added and other layout let say
Student2MarksLayout with same 2 spinners and a TextView . Now in
this case on the click listener of TextView I am getting the value
of spinners which are currently added. even though i click on the
TextView of the Student1MarksLayout. It brings the values of
Student2MarksLayout values.
Question:
So in fact I want to get the values of spinners differently from the
same view group in which the TextView click has been originated by the
user.
Please help me and any suggestion about this on how to maintain this .
On the function that creates the layout, add to final variables that hold the 2 Spinners. Then create the onClick function, and reference these 2 final variables. I have written a quick example (in a bit of shorthand)
void createLayout()
{
View v = inflate....
final Spinner a = v.findViewById...
final Spinner b = v.findViewById...
TextView t = v.findById...
t.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
int val = a.get....
}
});
}
I am dynamically adding views to Android and am seeing a really weird result which makes little to no sense. Here is the code that shows the bug:
private static int count = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
count++;
// Allow 'up' action for actionBar
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("TEST");
setContentView(R.layout.test);
LinearLayout testLinear = (LinearLayout)findViewById(R.id.testLinear);
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.job_step_text, null, false);
TextView title = (TextView) view.findViewById(R.id.jobStepTextTextView);
final EditText editText = (EditText)view.findViewById(R.id.jobStepEditText);
title.setText("Field 1");
editText.setText("Value 1");
testLinear.addView(view);
if(count == 1) {
View view2 = inflater.inflate(R.layout.job_step_text, null, false);
TextView title2 = (TextView) view2.findViewById(R.id.jobStepTextTextView);
final EditText editText2 = (EditText)view2.findViewById(R.id.jobStepEditText);
title2.setText("Field 2");
editText2.setText("Value 2");
testLinear.addView(view2);
}
}
First time round the Activity is as follows:
Field 1: [ Value 1 ]
Field 2: [ Value 2 ]
Then when the device rotates the following is shown:
Field 1: [ Value 2 ]
Can anyone help? It seems that after the first time round the line:
final EditText editText = (EditText)view.findViewById(R.id.jobStepEditText);
is fetching an old reference and not calling setText()? When the screen rotates the line of code which sets the text field to 'Value 2' isn't even called and yet that's the result in the Field 1 text box.
Can anyone help?
By the way - a way to fix this is to give each EditText a unique ID before adding it to the view... but that makes no sense... Surely the inflated View has no knowledge of any other views (past or present) until testLinear.addView(view); is added?
Thanks in advance.
The onSaveInstanceState in the Activity (your super class) captures information about the attached content view and reloads it for you during onCreate() So when the Activity gets recreated after the device rotates, values are put into views found by ID as soon as you call setContentView(). This can produce surprising results if you are changing your layout on-the-fly.
One approach I have used is to call findViewById to see if the child view is already present, before adding it "by hand".
Another approach would be to inflate the layout first, make your adjustments to it, then call setContentView.
[I don't quite understand Android's reason for doing this -- maybe to allow super-simple applications to skip the onSaveInstanceState/reload from bundle process??)
I'm new to android, so maybe I'm doing something horribly wrong. I want to have a particular Activity that shows details about an instance of a "Creature" class for a game. Name, damage taken, that sort of thing.
I'm having a problem getting the creature data to be properly shown in the GUI objects. Both at initial creation (where it should copy the creature's name into the name field) and when a damage mark is added (where it doesn't update to show the proper image).
Here's my mini-example of what I have:
public class CreatureDetailActivity2 extends Activity
{
Creature creature;
public void addMark(View v)
{
// connected to the button via android:onClick="addMark" in the XML
creature.getTrack().addDamage(DamageType.Normal, 1);
refreshDisplay();
new AlertDialog.Builder(this).setTitle(creature.getName())
.setMessage(creature.getTrack().toString()).show();
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_creature_detail);
creature = new Creature("Example");
refreshDisplay();
}
public void refreshDisplay()
{
final View creatureDetailView = this.getLayoutInflater().inflate(
R.layout.activity_creature_detail, null);
final EditText nameField = (EditText) (creatureDetailView
.findViewById(R.id.textbox_creature_name));
nameField.setText(creature.getName());
final ImageView damageBox0 = (ImageView) (creatureDetailView.findViewById(R.id.damageBox0));
damageBox0.setImageResource(R.drawable.__n);
// in the full program this does the same for 0 through 9, but this is a sample
// also, in the full program, this is a dynamic lookup for the correct pic
// but again, this is just a sample version.
}
}
Now the problem is that the app will load up and start, but then none of the widgets will update properly. You can click the button, and it'll show the AlertDialog, and the text of the AlertDialog will change, but the textfield in the activity won't be changed, and the ImageView doesn't change at any point from what it starts as to the one it's supposed to change to.
So I'm very stumped. I can post more about the project's setup if I'm leaving out something important, but I'm not even sure what the problem going on is so I'm not sure what else to include in my question.
final View creatureDetailView = this.getLayoutInflater().inflate(
R.layout.activity_creature_detail, null);
Inflates your Activity's layout into basically nothing, just returning the View it inflated. setContentView is what actually inflates your layout into the Activity's View hierarchy.
Once you inflate your layout you don't need to do it again. Just use findViewById without the reference to a dangling unattached View.
Change your refreshDisplay method to this:
public void refreshDisplay()
{
final EditText nameField = (EditText) findViewById(R.id.textbox_creature_name);
nameField.setText(creature.getName());
final ImageView damageBox0 = (ImageView) findViewById(R.id.damageBox0);
damageBox0.setImageResource(R.drawable.__n);
// in the full program this does the same for 0 through 9, but this is a sample
// also, in the full program, this is a dynamic lookup for the correct pic
// but again, this is just a sample version.
}
Nothing changes because You do it completely wrong.
If You wish to update any view element of current activity You do it like this
View v = findViewById(R.id.element);
v.setText("text");
this is just simple example.
You would need to cast a returned element to correct type like to be able to access all available methods.
What You do wrong is trying to inflate a layout again.
I create a dialog and populate it with a listview that uses a custom list adapter. It works fine, but I've noticed that when the list is long enough to scroll, doing so back and forth will cause some of my list items to randomly lose some of their data. I've noticed it is always the same list items too. For instance, each list item will have a title, image, and date on it. The dates seem to vanish on some when I scroll. They are always there when I start the dialog, and they always vanish once I scroll.
The weird thing is that my list row consists of a few TextViews in 2 rows and its only the bottom row TextViews that dissapear...Any ideas?
Code for my dialog
itemSendPickerDialog = new Dialog(this);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Select Item to Send");
ListView lv = new ListView(this);
Cursor c = mDbHelper.fetchItemsByDate(id);
c.moveToFirst();
int i = R.layout.send_item_menu_row;
MyListAdapter ia = new MyListAdapter(this, mainListBackground, c, true);
lv.setAdapter(ia);
builder.setView(lv);
itemSendPickerDialog = builder.create();
itemSendPickerDialog.show();
And my custom list adapter class:
class MyListAdapter extends ResourceCursorAdapter {
public MyListAdapter(Context context, int i, Cursor cursor, boolean...sending) {
super(context, i, cursor);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.item_name);
title.setText(cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_TITLE)));
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getWidth();
width = width - 150;
ViewGroup.LayoutParams params = title.getLayoutParams();
params.width = width;
title.setLayoutParams(params);
String cat = cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_CATEGORY));
if (cat.equalsIgnoreCase("trip notes")) {
LinearLayout ll = (LinearLayout) view.findViewById(R.id.item_datetime_holder);
ll.setVisibility(View.INVISIBLE);
}
TextView date = (TextView) view.findViewById(R.id.item_date);
date.setText(cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_DEP_DATE)));
TextView time = (TextView) view.findViewById(R.id.item_time);
time.setText(cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_DEP_TIME)));
ImageView iv = (ImageView) view.findViewById(R.id.image_icon);
if (iv != null) {
int index = cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_TYPE);
String type = cursor.getString(index);
if (type != null) {
} else {
type = "notes";
}
iv.setImageResource(getTypeResource(type));
}
}
}
I have faced this problem too...
The problem you are facing is due to the recycling of views by the LIstView when you scroll up/down. In your case, the ListView is giving you those recycled views , whose properties you have changed by making them invisible. Some possible solutions could be:
1) When cat.equalsIgnoreCase("trip notes")) is becoming true, you are making some views invisible. This invisible view is then recycled and given back. The recycled view is still invisible (when it is given back to you), so what you can do is make this invisible view visible in the beginning of your ListAdapter every time .
You can put this code at the beginning of bindView method where you make the layout visible first and then proceed with rest of the logic.( In short, the dates from your display are not vanishing but are just invisible).
2) Override getViewTypeCount() in you adapter . From your codesnippet, it looks like you have two types of rows( one in which R.id.item_datetime_holder is invisible and other in which it is visible) , so return 2 from this method( please do some trial and error ) . This should take care of the problem.
public int getViewTypeCount() {
return 2;
}
You will find an excellent explanation at this link http://logc.at/2011/10/10/handling-listviews-with-multiple-row-types/
3) You can inflate completely different layouts depending on your if condition. But the effeciency would be a little less.
I had a similar problem, when scrolling a list, only the items after the window height decided to get their data repeating from index 0 - so if the last visible item was 8, the next would be 0 again.
So you could try to check if the index of the view is correct, maybe this method of ListView would help
lv.getPositionForView(view);
I've figured out that the code that is doing this is in my custom list adapter class
String cat = cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_CATEGORY));
if (cat.equalsIgnoreCase("trip notes")) {
LinearLayout ll = (LinearLayout) view.findViewById(R.id.item_datetime_holder);
ll.setVisibility(View.INVISIBLE);
}
I hide some of the layout items depending on what the category is, and for some reason when putting a list view in an AlertDialog builder it appears to mix up the items. I don't know exactly how I am going to fix it, but for now if I just remove the invisibility functionality, my data won't go away.
I would use two different layouts, depending on the "type" of list item. It looks like you are switching the "type" based on the cat string containing "trip notes". If it contains it, then you would have a layout that is the same as you have now, but without the item_datetime_holder view. If it doesn't contain it, then you would use the same layout as you're using now (send_item_menu_row).
Here is a good tutorial on how to use multiple layouts in a ListView: http://android.amberfog.com/?p=296
By the way, I think that the reason why some of your rows are not drawing correctly is due to view reuse by the ListView. Utilizing the multiple layouts like I've mentioned above should fix the problem since you won't be changing the visibility of views, but just utilizing two different views to render, depending on what type of list item you're rendering.
So, is there any easy way to identify the tablerow clicked?
I have a tablelayout with static data, like a menu. When the user click any tablerow I want to start the specified activity.
I've googled a couple of hours but everyone seem to use the view inside the tablerows text property to identify it, which sucks if you translate the app. I tried to find some getIndex property of the TableLayouit but no luck, and the views .getId property is useless.
I guess the solution is to have specific onclicklisteners on each tablerow but that will generate a lot of (unnecessary) code and there must be a better solution?
Regards
if you make your activity as an extension of ListView() and you put your options in a list you can actually override the method
public void onListItemClick(ListView parent, View v, int position, long id) {
}
and the position attribute of that method is an int which indicates what row you actually click
this is a solution that i am sure actually works, so if your table layout is not too complicated i suggest you to make a list and override this method!
ok, I'll try another one since that one causes you other problems, you could make something like this:
in the onCreate():
firstTextVIew = (TextView) findViewById(R.id.firstText);
firstTextView.setOnClickListener(this);
secondTextVIew = (TextView) findViewById(R.id.secondText);
secondTextView.setOnClickListener(this);
after the onCreate():
public void onClick(View v) {
/*make a list of cases for any text view, where __TextView is the name you gave to the textview when you made the getViewById() on the start of the activity*/
if(v == firstTextView){
//start activity
}
if(v == secondTextView){
//start activity
}
}