App blocks with no error when redrawing GUI with setContentView - android

I create a layout in code in onCreate. Inside this layout, i have spinner with registred listener. When user changes item in a spinner, new data is read and layout must be changed according to data. I do this with the same function as in onCreate (i create scrollview and other views and call setContentView(scollView) on the last line).
The layout changes correctly but everything blocks, spinner and buttons can't be clicked anymore. Logcat displays no error(only lots of GC freed x objects).
I tried calling scrollview.removeAllViews() before trying to redraw layout, but that doesn't help either.
What am i missing here?

Presumably you are creating a whole new set of button and spinner objects. You need to register all the Listeners again to these new objects.

I found a problem in my onItemSelected function, where i forgot to change boolean "firstTime", so this function was called over and over.
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (firstTime) {
//do nothing (just change the flag) because we don't want this called during UI building
firstTime=false;
}
else {
posit=pos;
String koda=Roaming.m.get(parent.getItemAtPosition(pos).toString());
Roaming.operaterji.clear();
Roaming.parsePrices(json, koda);
getAll();
firstTime=true; //FORGET TO SET FLAG BACK TO TRUE, SO THIS WAS CALLED IN A LOOP
makeGui();
}
}

Related

Android Spinner remove OnItemSelectedListener

Others has the problem as doesn't working, I have the problem it is working ( and it shouldn't )
I have a data model, which is saved, and need to loaded back to GUI, Activity. It has a few spinner value.
The data is place to a common accesible class, a reference holder.
The activity's onCreate it will check if is on edit mode or not with:
editMode = getIntent().getBooleanExtra(EDIT_MODE_KEY, false);
It will load the UI elements from xml, and start selecting, filling values.
At editing mode, and at creation mode it should select values what has the data model.
At runtime ( after onResume() ) has some workflow: is something is selected at spinner1, than should refresh the spinner2 adapter content and so on.
It doesn't worked the plain .setSelection(positiontoSelect); so I have added a delayed post, now is working.
My problem is: I would like remove for temp the selection listener, call the selection and add back the listener.
Here is the code, which should be modified:
if (editedTimezonePosition > -1) {
final int positiontoSelect = editedTimezonePosition;
new Handler().postDelayed(new Runnable() {
public void run() {
OnItemSelectedListener listener = spSelectTimezone.getOnItemSelectedListener();
spSelectTimezone.setOnItemSelectedListener(null);
spSelectTimezone.setSelection(positiontoSelect);
spSelectTimezone.setOnItemSelectedListener(listener);
}
}, 250);
}
setting to null the listener has no effect: I am getting callback to my listener method.
If you have any idea how to fix it, please share it!
You could put a counter variable in your onItemSelected method. If it is 0 (meaning the first time the method has been called), do nothing but increment the variable. If it is greater than 0, execute the rest of your code.
private int mSpinnerSelectionCount=0;
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
if(mSpinnerSelectionCount == 0){
mSpinnerSelectionCount++;
} else {
// Your normal selection code here
}
}

ListView getChildAt() stays null BUT if in onclick it works

I have a ListView that is filled with items of an ArrayAdapter.
Now I want to strike them out when click and also check in the beginning if they are already struck through(calling an external api etc).
But it only works in the onItemClickListener the method above it doesn't.
to understand it better, here is some code:
public void machListe() {
listViewArrayAdapter = new ArrayAdapter(getApplicationContext(),R.layout.task_item, ti);
taskListe.setAdapter(listViewArrayAdapter);
TextView ab=(TextView) taskListe.getChildAt(0);
So if I Debugg now I see that ab is null.
taskListe.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3) {
TextView ab=(TextView) taskListe.getChildAt(0);
If I debug here, ab is NOT null.
You are trying to saft the state of the tasks inside your Views.
You should try to separate Model and View at this point.
Create a Model Object that contains a single task then extend ArrayAdapter and overwrite getView. In the getView you retrieve the correct task from the task list. Create the textview for the task and if the task is marked as done in your model you cancel out the text.
If you try to change the views in a list after they are created you would have to do this every time the list stops scrolling because the list will only hold childviews for the items that are shown on the screen, the other views are created during scrolling to save memory.
The only correct place to change a listview Item is in the getView method of the corresponding Adapter.
Have a look at the ListsView Tutorial on vogella.de for more information.
Setting the adapter will trigger a requestLayout but the actual layout is not done yet.
So taskListe won't have child-views yet when you call getChildAt(0) immediately after calling setAdapter
Here is the code and 2 is the index value
View view=adapter.getView(2, null, null);
TextView textView = (TextView) view.findViewById(R.id.textView1);
String value = textView.getText().toString();

Cannot use onItemSelectListener() with Spinner with One Item

So I have a spinner (spinner2 here) which is populated via an ArrayAdapter from an SQLite table. On selecting an item I want it
deleted from the DB
deleted from the spinner
The code below actually works. Except when the spinner has only one item. When that happens
it seems onItemSelected is not called at all.
I get the following LogCat
10-01 22:30:55.895: WARN/InputManagerService(1143): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#45a06028
Oh and when two items are populating the spinner, spinner.getcount() shows two items, so it's not some strange case of the system thinking the spinner is empty or something like that.
This is the code:
public class SpinnerItemSelectListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if(parent == spinner2){
if(autoselected){
autoselected=false;
}
else{
//uniqvalarray is the arraymade from pulling data from SQLite and populaitng array adapter
Integer i = uniquevalarray.get(pos);
deleteRow(i);//deletes the row from the database and repopulates the above array.
autoselected=true;//just a boolean to stop autoslecting in onCreate()
//makeAlert(i);initially wanted to make alert box.
loadSpinner2();//reloads the spinner with new data
}
}
}
public void onNothingSelected(AdapterView parent) {
//TODO
}
}
The spinner runs this way : Only fire when you change the selected item . If you dont change that element , cause its the only one that exist , it can't change .
The solution i think you must use is using a button next to the spinner to throw the delete funcions.
You must think that Spinner is not made to be with an unique element , cause only changes usually when you change the selected one . then the natural solution can be that .

How to get the view of a ListView item?

I have two ListViews (A and B) with items of the same type (a class I created)
When I click on an item from A, it adds this object on B and if I click again it removes it.
Only that when an item is selected, I change its background using view.setBackgroundColor(myColor).
I want to be able to remove the item from list B (it works), but I want also to reset the background color. I can't figure out how to get the view of this item I'm removing.
Any ideas?
There's no guarantee that any specific ListView item will even have a view at any given time. If the item is currently off-screen, then it may not have a view. Since a specific item might not have a view, it might not make any sense to try to get the item's view.
Beyond that, because of the way ListView creates and reuses views, you'll see some odd, undesirable effects if you simply modify the views directly. As the user scrolls through the list, items that become visible will incorrectly end up with the same backgrounds as other items that have fallen outside the visible portion.
I don't know whether what follows is the best way to implement your functionality because I don't know the cost of rebuilding the list after a change. Here's the (probably naive) way I would do this:
Add another boolean member to your data object, something like isInSecondList.
Override getView() in the Adapter. In getView(), set the background to either normal or highlighted depending on the the value of the item's isInSecondList.
When an item is added or removed from the second list, update the data object to reflect the change, then call the Adapter's notifyDataSetChanged().
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
Here is what i did
private View oldSelection;
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long arg3) {
highlightSelectdListItem(position);
}
public void highlightSelectdListItem(int position) {
clearPreviousSelection();
View newsItemView = mGridVIew.getChildAt(position);
oldSelection = newsItemView;
newsItemView.setBackgroundColor(Color.GRAY);
}
public void clearPreviousSelection() {
if (oldSelection != null) {
oldSelection.setBackgroundColor(Color.TRANSPARENT);
}
}

Update ListView from user input after setContentView call

I want to show an empty list view, which is then populated by user input. I have the UI flow working, and I populate a list of my custom objects after the user enters some information via a view which is invoked through setContentView (i.e. no a new Activity).
I take the input and add it to a list, which I want to be summarised on the ListView. However, whenever I add to the list and/or the ArrayAdapter and call adapter.notifyDataSetChanged() it does not do what I want. The ListView is still empty. Argh! It's driving me insane!
#Override
public void onCreate(Bundle blah) {
ListView listView = (ListView) findViewById(R.id.results_list);
listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, list));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.mnu_add:
final Activity act = this;
setContentView(R.layout.record_details);// the sub-view that takes the user input
// the button on the form to 'add' details:-
((Button) findViewById(R.id.recored_details_add_btn))
.setOnClickListener(
new OnClickListener() {
public void onClick(View v) {
// get input from widgets
list.add(someObject);
((ArrayAdapter<Object>) listView.getAdapter()).notifyDataSetChanged();
setContentView(R.layout.list_view);
}
}
);
((ArrayAdapter<Object>) listView.getAdapter()).notifyDataSetChanged();
break;
}
return true;
}
Please, save me from my misery and inform me of my stupidty?
Thanks in advance.
public void onClick(View v) {
// get input from widgets
list.add(someObject);
((ArrayAdapter<Object>) listView.getAdapter()).notifyDataSetChanged();
setContentView(R.layout.list_view);
Is it possible that this setContentView in the onClick handler is creating a new instance of the list view widget (with no adapter) or reinitializing the list view (clearing the adapter)?
Try putting something in the list initially in onCreate and then see if it disappears when you hit the button.
I haven't seen any code (although I'm a relative newbie) that switches views within the activity's lifetime to bring up essentially bring up different pages - most use a separate activity.
Edit:
OP asks:
Thanks...So how can I get what I want? The list I'm backing the adapter with is static; should I just use activities instead and rely on onCreate loading from the static field?
Some options:
Use separate activities
Re-associate the adapter (call setAdapter again) - probably a bad idea
Declare both layouts in the same file. You'll hide one and unhide the other to switch between views rather can calling setContentView. This is similar to how ListView layout works (one for when the list is empty and one for when it is not). I think I've seen an example of this somewhere on the net, but I don't have a reference right now.
You could relaunch the same activity by using Intent.FLAG_ACTIVITY_SINGLE_TOP flag while creating the intent and override the onNewIntent() method.
Inside the onNewIntent() you create the adapter with updated data and call setAdapter.
I think this will give you the intended behaviour.

Categories

Resources