ListView disappears when adding a view from CursorAdapter - android

My layout includes an unpopulated horizontal linear layout with a multicolumn listview below. The listview is populated from an sqlite table via a custom cursor adapter in a separate java file. each time a particular view in a listview row is tapped, a button is dynamically created and added to the linear layout. For reasons I don't understand, when this happens, the listview content disappears. If I change the orientation of the device, it goes through the onCreate and the display builds correctly with the linear layout buttons showing correctly over the listview.
The main layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/llRunnerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
</LinearLayout>
</HorizontalScrollView>
<ListView
android:id="#+id/list_data"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
and the view listener code in the custom cursor adapter:
private OnClickListener strRunnerOnClickListener = new OnClickListener() {
#Override
//
// When the Runner field is clicked, add the Runner name to the Runner row.
//
public void onClick(View v) {
final DBAdapter databaseHelper = new DBAdapter(ctxThis);
LayoutParams params =
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
TextView tvRunner = (TextView) v;
String strRunner = (String) tvRunner.getText();
if(RaceSheetActivity.blnRaceRunning) {
// get the ListView and the position in it.
ListView lv = (ListView) v.getParent().getParent();
final int position = lv.getPositionForView((View) v.getParent());
// get the cursor pointing to that row
Cursor c = (Cursor) lv.getItemAtPosition(position);
long lngCurrentId = c.getInt(0);
long lngRaceId = c.getInt(1);
c.close();
// Add to database if doesn't exist
Cursor cSNRec = databaseHelper.getSNRecByCompetitorId(lngCurrentId);
if(cSNRec.moveToFirst()) {
Toast.makeText(v.getContext(), strRunner + " already in preempt list!", Toast.LENGTH_SHORT).show();
}
else {
databaseHelper.insertSN(strRunner, lngCurrentId);
// Add a button and initialise it
ToggleButton btnRunner = new ToggleButton(ctxThis);
btnRunner.setText(strRunner);
btnRunner.setTextOn(strRunner);
btnRunner.setTextOff(strRunner);
btnRunner.setTag(lngCurrentId);
btnRunner.setLayoutParams(params);
btnRunner.setOnClickListener(RaceSheetActivity.btnRunnerOnClickListener);
RaceSheetActivity.llRunnerList.addView(btnRunner); // to delete view removeViewAt(int index)
changeCursor(databaseHelper.getRaceSheetDataForRace(lngRaceId));
notifyDataSetChanged();
}
}
}
};
Would really appreciate any ideas as to how I can keep the listview visible after tapping the runner field and the button appearing. I have tried notifyDatasetChanged without success, reread the database table into the cursor adapter.

Set your layout heights to wrap_content because your ItemList with the buttons will overlap your Listview if it's not empty.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/llItemList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
<ListView
android:id="#+id/list_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

Actually you are not initializing the HorizontalScrll view And just close the Horizontalscrollview due to that App return this type of behaviour

Actually, solved the problem eventually. The listview was disappearing because I had used a cursor to get the adapter values for the row that was returned, and subsequently closing the cursor apparently cleared the listview.
Thanks to both those who offered solutions albeit they weren't the cause of the problem.

Related

Android complaining about content not having Listview with id android.R.id.List despite having that

obviously not a profound question, but I think theres probably an error in my approach.
So I've added the file listview.xml to my project in the layout folder.
it contains this:
<?xml version="1.0" encoding="utf-8"?>
<ListView android:id="#+id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" />
I've also tried:
<?xml version="1.0" encoding="utf-8"?>
<ListView android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" />
And i my main activity function generally looks like this:
public class ToDoManagerActivity extends ListActivity {
private static final int ADD_TODO_ITEM_REQUEST = 0;
private static final String FILE_NAME = "TodoManagerActivityData.txt";
private static final String TAG = "Lab-UserInterface";
// IDs for menu items
private static final int MENU_DELETE = Menu.FIRST;
private static final int MENU_DUMP = Menu.FIRST + 1;
ToDoListAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a new TodoListAdapter for this ListActivity's ListView
mAdapter = new ToDoListAdapter(getApplicationContext());
// Put divider between ToDoItems and FooterView
getListView().setFooterDividersEnabled(true);
// TODO - Inflate footerView for footer_view.xml file
TextView footerView = (TextView) getLayoutInflater().inflate(R.layout.footer_view, null);
// NOTE: You can remove this block once you've implemented the assignment
if (null == footerView) {
return;
}
// TODO - Add footerView to ListView
getListView().addFooterView(footerView);
setListAdapter(mAdapter);
setContentView(R.layout.footer_view);
This keeps breaking with the error:
...java.lang.RunTimeException: content must have a ListView whose id attribute is 'android.R.id.list'
I noticed that if I comment out the setContentView(R.layout.footer_view) bit the error disappears, which is quite confusing as well, because it seems like the error should trigger before there.
This is confusing the hell out of me because as far as I can tell this element exists. Its seems like maybe I'm missing a step to load the ListView? I'm banging my head against the wall here and this seems like something really basic, and being a n00b sucks...So any help is much appreciated!
Cheers!
EDIT:
footer_view.xml contents:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/footerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#string/add_new_todo_item_string"
android:textSize="24sp" >
</TextView>
EDIT2:
Current onCreate after suggested edits:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create a new TodoListAdapter for this ListActivity's ListView
mAdapter = new ToDoListAdapter(getApplicationContext());
// Put divider between ToDoItems and FooterView
getListView().setFooterDividersEnabled(true);
setListAdapter(mAdapter);
TextView footerView = (TextView) getLayoutInflater().inflate(R.layout.footer_view, getListView(), false);
getListView().addFooterView(footerView);
}
For an Activity that is extending ListActivity, the ListView needs to exist within the xml file that you are using in the activity, in your case that's the footer_view file.
Taken from the Google Dev Site - "ListActivity has a default layout that consists of a single, full-screen list in the center of the screen. However, if you desire, you can customize the screen layout by setting your own view layout with setContentView() in onCreate(). To do this, your own view MUST contain a ListView object with the id "#android:id/list""
To incorporate your footer below your list, try this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="#+id/footerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#string/add_new_todo_item_string"
android:textSize="24sp" >
</TextView>
</LinearLayout>
Here, try this in your layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:id="#android:id/list" />
</LinearLayout>
That is exactly what I have in my app.
Then in your onCreate(), just this:
setContentView(R.layout.activity_main);
Try it and let me know if it works. That code should work. From there, we can continue on to isolate the problem.
EDIT:
Man, now I see your problem. Not a big deal here. Let's look at your code (edited to be shorter). The onCreate() method has this:
super.onCreate(savedInstanceState);
mAdapter = new ToDoListAdapter(getApplicationContext());
getListView().setFooterDividersEnabled(true);
TextView footerView = (TextView) getLayoutInflater().inflate(R.layout.footer_view, null);
getListView().addFooterView(footerView);
setListAdapter(mAdapter);
setContentView(R.layout.footer_view);
Do you see R.layout.activity_main anywhere there? There's your issue! Your R.layout.footer_view only contains a textview, it doesn't contain the ListView, and your Activity keeps looking for the ListView that you promised it that you'd have by extending a ListActivity.
Try this - change your onCreate() method to this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = new ToDoListAdapter(getApplicationContext());
setListAdapter(mAdapter);
}
Then your activity_main.xml layout file should look like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:id="#android:id/list" />
</LinearLayout>
This should work. Let me know.
EDIT2:
Now add this to the end of your onCreate() method:
TextView footerView = (TextView) getLayoutInflater().inflate(R.layout.footer_view, null);
getListView().addFooterView(footerView);
Voila! Should work now.

ListView with setOnItemClickListener not work with button

I have a listview with buttons in each row in fragment, the number of buttons retrieve based on sqlite database. I want to make when button click it move to an another new activity and parse button names. But when i click the buttons nothing happens, i have already try to use this code in xml file from ListView setOnItemClickListener not working by adding button, but it still not working.
android:focusable="false"
android:focusableInTouchMode="false"
android:descendantFocusability="blocksDescendants"
Does anyone have solution? Thanks before and below is my code.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
DatabaseHandler db = new DatabaseHandler(getActivity());
listView = (ListView) getView().findViewById(R.id.list_addcard);
List<CardType> listCardType = db.getAllCardType();
for(CardType ct : listCardType){
String log = "ID: " + ct.getTypeId() + " Category Name: " + ct.getTypeCategory();
Log.d("Result: ", log);
categoryArray.add(ct);
}
adapter = new ListAdapterAddCard(getActivity(), R.layout.list_row_addcard, categoryArray);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View v, final int position, long id){
categoryName = categoryArray.get(position).getTypeCategory();
Intent intent = new Intent(getActivity(), DetailCategory1.class);
intent.putExtra("categoryName", categoryName);
startActivity(intent);
}
});
}
listview.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background">
<ListView
android:id="#+id/list_addcard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#null"
android:layout_marginTop="30dp"/>
</RelativeLayout>
listrow.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="8dp"
android:descendantFocusability="blocksDescendants">
<Button
android:id="#+id/category_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/category"
android:focusable="false"
android:focusableInTouchMode="false"/>
</RelativeLayout>
Firstly remove the following from your button xml..
android:focusable="false"
android:focusableInTouchMode="false"
then in your custom adapter where you inflates your custom xml cell in the list, get the button reference and set the onclick listenet over there for that button.
For me it did not work having an startActivity function within the application as within the function you don't have access to the context, you need to add the variable of the host activity. Basically I think you need to do the following:
Activity host = (Activity) listView.getContext();
Intent intent = new Intent(host, DetailCategory1.class);
....
host.startActivity(intent);
This is what I need to do in getView method of my adapter for an standard listview.
category_name Button is stealing the focus from the ListView item, you could either add onClick listener to the each item button or simply use TextView instead styled as Button, this is a very bad practice though and confusing to your users
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="8dp"
android:descendantFocusability="blocksDescendants">
<TextView
android:id="#+id/category_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/category"
style="#android:style/Widget.Button"/>
</RelativeLayout>
First you need to set clickable to your custom layout button in your case
<Button
android:id="#+id/category_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/category"
android:clickable="true"/>
Next, you are setting the OnItemClickListener to the "ListView" (<< parent) itself not the
(Button>>) children listView.setOnItemClickListener(new OnItemClickListener(){
BUT,
you can get a reference to the category_name button once you have inflated your ListView by doing something like this;
Button myButton = (Button) list_addcard.findViewById(R.id.category_name);
If you need more help you can always visit the Android Documentation for
ListView ListView Documentation
Cheers.
So finally i found the answer, i change the setOnClickListener to my adapter class and it's work fine for me. Thank you all for your suggestion.
holder.txtCategoryName.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(context, DetailCategory.class);
int pos = (Integer) v.getTag();
categoryName = categoryItems.get(pos).getTypeCategory();
intent.putExtra("categoryName", categoryName);
context.startActivity(intent);
}
});

Android: ListView with expanding LinearLayouts as items causes duplicates

I'm trying to write a test application that consists of a few fragments.
One fragment should contain a listView of all music artists from the device.
Each item of this list is a linearlayout starting with a TextView with the artist name and an empty linearlayout under it as follows:
The list is of this layout:
<ListView
android:id="#+id/artistsLists"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
</ListView>
Each item is of the following layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/artistName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="" />
<LinearLayout
android:id="#+id/artistsAlbums"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
I'm populating the list using a SimpleCursorAdapter in the following way:
public class MusicTabFragment extends Fragment
{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_music_tab,container,false);
Cursor artistsCursor = getActivity().getContentResolver().query(Audio.Artists.EXTERNAL_CONTENT_URI, new String[]{Audio.Artists.ARTIST,Audio.Artists._ID}, null, null,Audio.Artists.ARTIST);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(view.getContext(), R.layout.music_artist_list_item_layout, artistsCursor, new String[]{Audio.Artists.ARTIST},new int[]{R.id.artistName},0 );
ListView lView = (ListView)view.findViewById(R.id.artistsLists);
lView.setAdapter(adapter);
lView.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
((LinearLayout)view.findViewById(R.id.artistsAlbums)).removeAllViews();
Cursor albumsCursor = getActivity().getContentResolver().query(Audio.Artists.Albums.getContentUri("external", ((Cursor)parent.getItemAtPosition(position)).getLong(1)), new String[]{Audio.Albums.ALBUM, Audio.Albums._ID},null,null,null);
LinearLayout artistLayout = (LinearLayout)view.findViewById(R.id.artistsAlbums);
for(albumsCursor.moveToFirst();!albumsCursor.isAfterLast();albumsCursor.moveToNext())
{
View albumView = LayoutInflater.from(view.getContext()).inflate(android.R.layout.simple_list_item_1,artistLayout,false);
((TextView)albumView.findViewById(android.R.id.text1)).setText(albumsCursor.getString(0));
artistLayout.addView(albumView);
}
Log.d("POPULATE","populated again!");
albumsCursor.close();
}
});
return view;
}
}
This works just fine. when i click an artist name, the linearlayout populates with all of this artist album names.
the problem is, that once a linearLayout scrolls out of view, it shows again from the other edge of the view (PacMan Style) as if another list item's linearLayout was populated.
It happens every time the expanded layout goes out of sight. the funny part is that some times when scrolling back up, the linearLayout shows under a different artist name.
example
I'll be glad to hear how should I implement this fragment. But i will also like to know why this behavior is caused.
Thanks,
Maor.
I have found the solution here at stackoverflow.com
It appears that the view shouldn't hold any data, since it is being used for different data when i scroll back and fourth.
I think holding an external data structure to save each virtual view state is not nice programming. is there a way to keep this data anyway? (for this i will be looking now)

android ListView doesn't get updated

As title says, my listview won't get filled.
I know that the adapter is getting filled with 3 items, debugged my way through it. But my xml isnt showing anything at all:
The adapter is a global variable if that should do anything.
Code:
private void listChange(CustomCursor c){
List<SimpleListItem> itemsList = new ArrayList<SimpleListItem>();
while (c.moveToNext()) {
String picture = c.getString("picture");
String text = c.getString("name");
itemsList.add(new SimpleListItem(text, picture));
}
productListAdapter = new ProductAdapter(getBaseContext(),R.layout.product_item, itemsList);
setListAdapter(productListAdapter);
productListAdapter.notifyDataSetChanged();
}
XML of the activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<dk.foo.views.PageHeaderView
android:id="#+id/header"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</dk.foo.views.PageHeaderView>
<ListView
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
Modify the orientation of your LinearLayout to vertical if you want to see the ListView.
Right now with the orientation of your parent LinearLayout set to horizontal and the width of your custom view PageHeaderView set to FILL_PARENT, your ListView is pushed out of the screen.

Android ListView select items to delete with 3 column layout

I'd like to implement a Listview in android in which I have the possibility to enable a delete mode, in which the user can select the entries to delete. It should be similar to the message application in android.
I already have a ListActivity which has an icon on the left and text on the right side. I now like to add a CheckBox floating on the right side of the list entry. The ListActivity is listed in another question by a friend of mine: android listactivity background color .
The layout should be:
Left Picture
Center List item
Right Checkbox for delete selection
How can I achieve this? Is there a standard ListView item in the framework I could use?
I guess you want a CheckBox to appear(only) when is time to delete items from the ListView. Assuming you use the layout from the other question:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:background="#color/darkbluelogo" >
<ImageView android:id="#+id/list_image"
android:layout_width="48dip"
android:layout_height="48dip"
android:contentDescription="#id/list_image"
/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="fill_parent"
android:padding="5dp"
android:background="#color/darkbluelogo"
android:scrollingCache="false"
android:cacheColorHint="#00000000" >
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#+id/title" >
</TextView>
<TextView
android:id="#+id/datetime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#+id/datetime" >
</TextView>
</LinearLayout>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
When the ListView starts the CheckBox will not be present and the content TextViews will occupy all the space. Add a flag in the getView method of your adapter that will signal that the CheckBox must be shown(here you will set the CheckBox's visibility from the layout to visible). When its time to delete items modify the flag and then call notifyDataSetChanged() so the ListView redraws its children, this time with the CheckBox present.
Note:
You'll have to store the status of the CheckBoxes yourself.
First of all you need a custom layout for your list entries. A simple RelativeLayout including an ImageView , a TextView and a CheckBox should be enough.
Then you might want to build your own custom adapter which can extend BaseAdapter (or SimpleAdapter or CursorAdapter or ArrayAdapter or...). The adapter will bind the list's data to your custom layout. If for example your data is contained in a Cursor it will look like:
private class MyCustomAdapter extends CursorAdapter {
public MyCustomAdapter(Context context) {
super(context, null);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
//Return a list item view
return getLayoutInflater().inflate(R.layout.my_custom_list_item_layout, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//Get views from layout
final ImageView imageView = (ImageView) view.findViewById(R.id.list_item_image);
final TextView textView = (TextView) view.findViewById(R.id.list_item_text);
final CheckBox checkBox = (CheckBox) view.findViewById(R.id.list_item_checkbox);
//Get data from cursor
final String text = cursor.getString(...);
//Add listener to the checkbox
checkBox.setOnClickListener(new OnClickListener() {...});
//Bind data
textView.setText(text);
}
}

Categories

Resources