While attempting to populate the items in a ListView following the outcome of a switch statement, I am encountering some sort of error. The application force closes inside the emulator, and when I ran it through the Eclipse debugger it shows the main thread has hung due to an IllegalStateException.
Aside from it meaning the obvious that it has entered some sort of wrong state, how do I fix it? I'm trying to do all of this from inside an OnItemClickListener, so that when the item is clicked, a switch statement evaluates which item was clicked, and then assigns an according ListAdapter to the ListView depending on the outcome of the switch. Is this the correct way to go about it? And if so, what in my code below is throwing the error?
final ListView lv = (ListView) findViewById(R.id.main_list);
final String[] autos = getResources().getStringArray(R.array.auto_array);
final ListAdapter la_auto = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_2, autos);
And then further down in the portion dealing with the onclicklistener
gallery.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView parent, View v, int position, long id)
{
switch(gallery.getSelectedItemPosition())
{
case 0:
lv.setAdapter(la_auto);
break;
EDIT: The LogCat stack trace is stopping at this error, "You must supply a Resource ID for a TextView, and the stack is hung at this point: ArrayAdapter.createViewFromResource(int, View, ViewGroup, int) line: 347
Any suggestions? I imagine it has something to do with the parameters I'm passing to the onItemClicked method.
Try android.R.layout.simple_list_item_1.
The answer is in simple_list_item_2.xml:
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
...
You need to use a resource that contains only a TextView. simple_list_item_1.xml fits the bill:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
...
Try browsing other possibilities here or making your own if you don't see any you like.
It would probably be better to start a new Activity with a new ListView and adapter.
You can pass the selected item as a parameter in your Intent:
Intent = new Intent(MyActivity.this, ActivityToStart.class);
intent.putExtra("selected", position);
startActivity(intent);
and retrieve it later in your other activity's onCreate method with:
int position = getIntent().getIntExtra("selected");
You may want to think about what information you would like to share between the activities. Using multiple activities will allow your user to press the back button and return to the original list as well.
Related
I am developing an app which uses two fragments. One of the fragments uses a ListView to display items and when clicked, the second fragment updates itself (it is a dictionary app).
Once an item is selected in the ListView, I want it to be highlighted. I achieved this by using the following properties in XML file for ListView item.
android:choiceMode="singleChoice"
android:listSelector="#android:color/darker_gray"
This works fine as far as selection of the item is concerned. But the problem is when I scroll the list, the selection sometimes stays on the at the bottom or top of the list (as the case may be) even though the selected item is not present in the list. Here are screenshots to explain my problem.
The first pic shows no selection; in second pic, I selected 101 and hence second fragment was updated. In the third pic, even though 101 is not shown, a part of the ListView is highlighted.
What's the issue ?
Thanks.
EDIT
Here is the OnItemClick() method.
public void onItemClick(AdapterView<?> arg0, View view, int arg2, long arg3) {
String selectedWord = words.get(arg2); //words in an ArrayList which holds all the words displayed in this fragment.
Meaning meaningFragment = (Meaning) getSupportFragmentManager().
findFragmentById(R.id.fragmentMeaning);
meaningFragment.searchMeaning(selectedWord); //this method updates the other fragment.
}
EDIT:
This problem is not resolved yet. I have uploaded the project on github if anyone wants to have a look.
In Eclipse you can create a Master-Detail Flow which is an example of what you are trying to do.
For this create a "New Android Application" and in the third or forth screen which is called "Create Activity", three possibilities are offered to you, select the one called "Master/Detail".
This does not provide an answer to your question but is just pointing you to a working example where you can elaborate from.
Now for the answer to your question, I looked at your code and found the mistake.
Here is the working code for the onCreateView(). I commented out the wrong lines of code.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v = inflater.inflate(R.layout.fragment_one, container);
listView = (ListView) v.findViewById(R.id.listView);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
//listView.setAdapter(new ArrayAdapter<String>(getActivity(),
// android.R.layout.simple_dropdown_item_1line, array));
//listView.setSelector(android.R.color.holo_blue_dark);
listView.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, array));
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
listView.setItemChecked(position, true);
FragmentTwo frag = (FragmentTwo) getActivity()
.getFragmentManager()
.findFragmentById(R.id.fragmentTwo);
frag.updateTextView(array[position]);
}
});
return v;
}
In your code the 2 following lines are wrong
listView.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_dropdown_item_1line, array));
listView.setSelector(android.R.color.holo_blue_dark);
what you do here is set a simple_dropdown_item_1line which is not what you want and you manually set the selector.
You have to use simple_list_item_activated_1 and not set the selector manually.
listView.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, array));
//listView.setSelector(android.R.color.holo_blue_dark);
If you want a custom selector color, you can create a custom selector by copying the simple_list_item_activated_1 and editing it to your needs and calling the edited layout.
However I recommend using the default colors so the day Android decides to change its color scheme you will be compliant to the new one.
In summary, to have the ListView.CHOICE_MODE_SINGLE working, you have to use simple_list_item_activated_1 and not manually set the selector.
I got a trivial code involving a ListView and a ArrayAdapter which throws a IndexOutOfBoundsException on some devices. The problem is: I do not know how this Exception occurs, I only get the stacktraces from the Developer Console of Android.
The reduced code example is shown below. How can the getItem operation of the ArrayAdapter fail for the position element? The ArrayAdapter is never changed, there is no other method in the Activity.
I know what a IndexOutOfBoundsException is, I know that I can prevent it by checking the length first. But I'm curious: How can this Exception happen here? How can someone click on a event which does not exist in the datastructure?
Reduced code:
public class EventListActivity extends Activity {
public void onStart() {
final ListView listview = new ListView(this);
final Event[] events = [Retrieve a Array from somewhere]
final ArrayAdapter<Event> a = new ArrayAdapter<Event>(this, R.layout.eventlistitem, events);
listview.setAdapter(a);
listview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Event event = a.getItem(position);
^^^^^^^ throws Exception
}
});
Exception:
java.lang.IndexOutOfBoundsException
at java.util.Arrays$ArrayList.get(Arrays.java:75)
at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:298)
at xxx.EventListActivity$3.onItemClick(EventListActivity.java:130)
Okay, I debugged it, in case someone has the same error, here is the solution:
If you use ListView.addHeader, the position argument of the onItemClick is shifted by 1. Seems quite weird because the position then has nothing to do with the position in the array-adapter. This SO Question contains the same conclusion, you have to pay attention what you add as headers.
My question above was in fact not very helpfull because the whole addHeader part was missing, it was impossible to answer the question by others, sorry. Nevertheless, this answer might be helpfull for others.
For example i have a video gallery. I scroll to a certain video click on it and a whole new activity starts. Whats the most efficient way to code this?
If you have a list, I'm sure you are getting a hold of it in the code and assigning an Adapter. You can define what happens (starting an activity) by defining setOnItemClickListener() as such:
final ListView list = (ListView)findViewById(R.id.myVideoList);
MyVideoAdapter adapter = new MyVideAdapter(this);
list.setAdapter(adapter);
list.setOnItemClickListener(new ListView.OnItemClickListener(){
public void onItemClick(AdapterView<?> av, View v, int position, long id){
MyVideoObject video = (MyVideoObject)av.getItemAtPosition(position);
Intent intent = new Intent(CurrentActivity.this, SelectedVideo.class);
intent.putExtra("video_id, video.getID());
startActivity(intent);
}
});
All you're doing above is to initializing the list and assigning what happens when the user clicks on the list item.
When a click happens, you're getting a hold of the video item (however you're juggling them between activities) and passing perhaps its ID to the new Activity you wanna launch. The new activity (SelectedVideo.class) can receive the ID in onCreate and perhaps play the video.
Hope this helps,
-serkan
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.
I currently have a list and would like to display a large amount of text once a list item has been clicked. The amount of text will vary depending on the list item that's been clicked, ranging anything from a paragraph to a number of paragraphs.
I'm still very much an Android noob, so any tutorials that you know of that relate to your answer would be most appreciated.
Thank you.
The specifics are up to how you want your App to look and feel, but I would say you cant go wrong with a textView with wrap_content for height and width, nested inside a scroll view.
Probably set that inside a custom dialog to pop up when the list is clicked, or make another activity to just show the text.
Depending on what type of information you are displaying, you might want to just have the ListView item redirect to an activity specifically for displaying this information in a nicely organized manner.
If there is going to be a lot of information (and interactivity such as links), then I recommend the new activity.
Pro: Flow! User can navigate back to your list.
Con: It's a new activity
Otherwise you could use a dialog or similar to show the information on the same activity as the list.
Short sample:
// bind your adapter here from database or wherever
String[] Columns = { "_id", "Name", "Description" };
int[] ItemIDs = { R.id.lbl_ID, R.id.lbl_Name, R.id.lbl_Description };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, Columns, ItemIDs);
ListView list_list= (ListView)findViewById(R.id.list);
list_list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView parent, View view, int position, long id)
{
try
{
Intent i = new Intent(getBaseContext(), ViewItemDetail.class);
i.putExtra("ID", ID);
// any other data you need to pass on to your view here. ID should let you select from a database or however you are pulling data
startActivity(i);
}
catch(Exception ex)
{
Log.println(1, "item-click-event", ex.getMessage());
}
}
});
// Then in your activity to get intent data:
Bundle extras = getIntent().getExtras();
if(extras !=null)
{
string ID = extras.getString("ID");
}