ListView with Custom Cursor Adapter is Empty - java

I am trying to implement a highscores activity, and i`m trying to use a ListView.
But there is a problem: list view shows me only an element what was added by .addHeaderView() method, but the adapter elements seem to be invisible.
Even though adapter.getCount() returns correct number of elements, they are somehow invisible.
Please help, I'm pulling my hair out here.
My Activity layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:keepScreenOn="true" >
<ListView
android:id="#+id/scores_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
My ListView row layout:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/name"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:paddingLeft="5dip"
/>
My activity code:
public class ScoresActivity extends Activity {
private ScoresAdapter adapter;
private ListView scoresList;
private Cursor cursor;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scores);
scoresList = (ListView)findViewById(R.id.scores_layout);
SQLiteDatabase dataBase = ((MyApplication) getApplication()).getDataBase();
cursor = dataBase.query(ScoresDBHelper.SCORES_TABLE_NAME,null,null,null,null,null,null);
adapter = new ScoresAdapter(this, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
scoresList.addHeaderView(getLayoutInflater().inflate(R.layout.scores_list_row, null));
scoresList.setAdapter(adapter);
Toast.makeText(this, String.valueOf(adapter.getCount()), Toast.LENGTH_LONG).show();
}
}
My adapter code:
class ScoresAdapter extends CursorAdapter{
LayoutInflater inflater;
public ScoresAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
inflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView textViewName = (TextView) view.findViewById(R.id.name);
textViewName.setText(cursor.getString(cursor.getColumnIndex("name")));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return inflater.inflate(R.layout.scores_list_row, null);
}
}

I was calling
cursor.close();
before onDestroy() method.

You need to add
android:layout_height ="wrap_content"
in your row layout's TextView.

Related

how can i code public class for SimpleCursorAdapter?

I am new to android and I need to use ListView for my project. I use a sample from the internet which has no public class for ListView so I am not able to code flexible. how can I code public class for this.
public class LIGHTS extends AppCompatActivity {
ListView users_list;
private DatabaseManager dbManager;
private SimpleCursorAdapter adapter;
private DatabaseHelper dbHelper;
final String[] from = new String[]{dbHelper._ID, dbHelper.TITLE, dbHelper.DESC};
final int[] to = new int[]{R.id.id, R.id.KEYCODE, R.id.NAME};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lights);
startconnection();
dbManager = new DatabaseManager(this);
dbManager.open();
Cursor cursor = dbManager.fetch();
users_list = findViewById(R.id.users_list);
adapter = new SimpleCursorAdapter(this, R.layout.adapter, cursor, from, to, 0);
users_list.setAdapter(adapter);}
and the fetch() is in below code in dbmanager:
public Cursor fetch() {
String[] columns = new String[]{dbHelper._ID, dbHelper.TITLE, dbHelper.DESC};
Cursor cursor = database.query(dbHelper.TABLE_NAME, columns, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
Here's an example based upon your code that handles clicking a button for each item in the list.
If you click a switch then it displays the id of the item via a toast.
This utilises a Custom Adapter based upon (extends) the CursorAdapter class.
First the layout adapter.xml used for the item (should have the basics of your's and includes a switch who's id is the_switch) :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/id"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/KEYCODE"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/NAME"
android:layout_width="0dp"
android:layout_weight="6"
android:layout_height="wrap_content" />
<Switch
android:id="#+id/the_switch"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:focusable="false"
/>
</LinearLayout>
The Activity Lights.java is now :-
public class Lights extends AppCompatActivity {
ListView users_list, alt_users_list;
private DatabaseManager dbManager;
private MyCustomCursorAdapter adapter;
//private DatabaseManager dbHelper; //?????? a second not needed
Cursor cursor;
Context mContext;
//<<<<<<<<<< Not needed although could be passed
//final String[] from = new String[]{DatabaseManager._ID, DatabaseManager.TITLE, DatabaseManager.DESC};
//final int[] to = new int[]{R.id.id, R.id.KEYCODE, R.id.NAME};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_lights);
startconnection(); //?????? dummied out
users_list = findViewById(R.id.users_list);
alt_users_list = findViewById(R.id.alt_users_list);
dbManager = new DatabaseManager(this);
dbManager.open();
manageListView(); //Handles the ListView
}
// Moved here handles list refresh if called (e.g. in onResume)
private void manageListView() {
cursor = dbManager.fetch();
//Setup the adapter if not already setup else swaps (refreshes) the cursor
if (adapter == null) {
adapter = new MyCustomCursorAdapter(this, cursor);
users_list.setAdapter(adapter);
users_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(mContext,"You clicked on the item with an ID of " + String.valueOf(id),Toast.LENGTH_SHORT).show();
}
});
} else {
adapter.swapCursor(cursor);
}
}
private void startconnection(){}
#Override
protected void onDestroy() {
super.onDestroy();
// Close the Cursors when done with them
cursor.close();
}
#Override
protected void onResume() {
super.onResume();
// Refresh the listviews when returning to the activity
manageListView();
}
}
Comments try to explain changes (basically it is quite similar).
The biggest change is that the setting up of the listview has been moved to a method of it's own, which also handles refreshing the listview (redisplaying it after the underlying data has been changed).
The instantiation of the adapter is also simpler than for the SimpleCursorAdapter (the layout and column to view handling coded in the adapter).
The adapter myCustomAdapter.java is :-
public class MyCustomCursorAdapter extends CursorAdapter {
public MyCustomCursorAdapter(Context context, Cursor c) {
super(context, c, 0);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (position % 2 == 0) {
view.setBackgroundColor(0xFFAAAAFF);
} else {
view.setBackgroundColor(0xAAAAAAFF);
}
return view;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.adapter,parent,false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView)view.findViewById(R.id.id)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
((TextView)view.findViewById(R.id.KEYCODE)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.TITLE)));
((TextView)view.findViewById(R.id.NAME)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.DESC)));
Switch thisswitch = view.findViewById(R.id.the_switch);
thisswitch.setTag(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
thisswitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Toast.makeText(buttonView.getContext(),
"You clicked the switch for ID " + (String) buttonView.getTag() +
" the status is now " + (new Boolean(isChecked)).toString(),
Toast.LENGTH_SHORT)
.show()
;
}
});
}
}
bindView has primarily been used it :-
binds the values from the columns of the cursor to the views for each item
and in this case sets the tag of the switch to the id and then adds an onCheckChangedListener for the Button.
bindView has the advantage that the cursor and context are passed to it.
getView can also be used, it has the advantage of having the position of the item in the list passed.
In this case it has been used to alternate the background colour for each item.
Result
Here's a screen shot showing the toast (note testing data was added to the underlying database, so this will obviously vary from yours) :-
Additional
It might be that you need to handle the switch check change in the owning activity.
The following changes show a basic means, via an interface, of handling the switch event in the activity, rather than in the adapter.
First the interface myOnCheckedChangedInterface.java
public interface myOnCheckedChangedInterface {
void myOnCheckedChangedHandler(String id, boolean check_status);
}
Second change Lights.java by adding the handler method myOnCheckedChangedHandler
#Override
public void myOnCheckedChangedHandler(String id, boolean check_status) {
Toast.makeText(
this,
"You changed the status for the row with an id of " + id +
" the status is now " + new Boolean(check_status).toString(),
Toast.LENGTH_SHORT).show();
}
Ignore the error that the method doesn't override method from it's superclass.
Third change the Class declaration to implement the interface by adding implements myOnCheckedChangedInterface as per :-
public class Lights extends AppCompatActivity implements myOnCheckedChangedInterface {
Lastly change MyCustomCursorAdapter to be able to call the myOnCheckedChangedHandler
e.g.
public class MyCustomCursorAdapter extends CursorAdapter {
Lights calling_activity; //<<<<<<<<<<########### ADDED for interface
public MyCustomCursorAdapter(Context context, Cursor c) {
super(context, c, 0);
this.calling_activity = (Lights) context; //<<<<<<<<<<########### ADDED for interface
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (position % 2 == 0) {
view.setBackgroundColor(0xFFAAAAFF);
} else {
view.setBackgroundColor(0xAAAAAAFF);
}
return view;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.adapter,parent,false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView)view.findViewById(R.id.id)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
((TextView)view.findViewById(R.id.KEYCODE)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.TITLE)));
((TextView)view.findViewById(R.id.NAME)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.DESC)));
Switch thisswitch = view.findViewById(R.id.the_switch);
thisswitch.setTag(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
thisswitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
/**
Toast.makeText(buttonView.getContext(),
"You clicked the switch for ID " + (String) buttonView.getTag() +
" the status is now " + (new Boolean(isChecked)).toString(),
Toast.LENGTH_SHORT)
.show()
**/
calling_activity.myOnCheckedChangedHandler((String)buttonView.getTag(),isChecked); //<<<<<<<<<<########### ADDED for interface
}
});
}
}
See commments with //<<<<<<<<<<########### ADDED for interface for changes
The original Toast has been commented out as it is no longer needed
Note this isn't the tidiest way as the Adapter is tied to a Lights activity, it's just meant to be a simple example.
In order to customize a ListAdapter, you need to create your own custom ListAdapter class that is based on, or 'extends' the built-in ListAdapter (such as SimpleListAdapter or BaseAdapter). Then, you can customize the appearance and what fields of data to display. Below is an example of a custom ListAdapter I called ClaimsListAdapter.java that 'extends' the built-in class called BaseAdapter:
package com.mycompany.myapp.adapter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import com.mycompany.myapp.ClaimListFragment;
import com.mycompany.myapp.R;
import com.mycompany.myapp.TripListFragment;
import com.mycompany.myapp.model.ClaimItem;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
// You might be able to extend SimpleListAdapter instead if you wish
public class ClaimListAdapter extends BaseAdapter {
private Context context;
private ArrayList<ClaimItem> claimItems;
ClaimListFragment fragment;
//I'm passing references to both the active Context as well as the active Fragment
//You might only need to pass the active Context
public ClaimListAdapter(ClaimListFragment fragment, Context context, ArrayList<ClaimItem> claimItems){
this.context = context;
this.claimItems = claimItems;
this.fragment = fragment;
}
#Override
public int getCount() {
return claimItems.size();
}
#Override
public Object getItem(int position) {
return claimItems.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#SuppressLint("InflateParams")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
//This is the layout for the list item. A SimpleListAdapter doesn't need one
//since it only has one text view, but this allows you to create multiple lines
//and/or multiple fields, buttons, checkboxes etc if you wish
convertView = mInflater.inflate(R.layout.claim_list_item, null);
}
//Get a reference to all of the items in the layout you wish to change
Button btnDelete = (Button) convertView.findViewById(R.id.claim_delete_in_list);
//Note, here I'm saving the row number in the tag of the button to tell the fragment
//which row in the array to delete.
btnDelete.setTag(position);
//Here is an example of setting a click listener for a button in the list
btnDelete.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Integer position = (Integer)v.getTag();
//Call the Public method in the parent Fragment (or Activity) to delete from the
//array and refresh the list
fragment.deleteItemList(position);
}
});
btnDelete.setVisibility(View.GONE);
//Get a reference to all of the text fields in the list item
TextView txtTitle = (TextView) convertView.findViewById(R.id.claim_title);
TextView txtStatus = (TextView) convertView.findViewById(R.id.claim_status);
TextView txtDate = (TextView) convertView.findViewById(R.id.claim_date);
TextView txtDistance = (TextView) convertView.findViewById(R.id.claim_distance);
TextView txtAmount = (TextView) convertView.findViewById(R.id.claim_amount);
String claim_title = claimItems.get(position).getDocumentID();
String claim_status = claimItems.get(position).getClaimStatus();
txtTitle.setText(claim_title);
txtStatus.setText(claim_status);
return convertView;
}
}
And the claim_list_item.xml layout file:
<?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="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/whole_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:background="#drawable/list_selector_light"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/top_layout"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_weight="0.48"
android:background="#00000000"
android:orientation="horizontal" >
<TextView
android:id="#+id/claim_title"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginBottom="2dp"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_weight="0.73"
android:background="#00000000"
android:gravity="start|center_vertical"
android:text=""
android:textColor="#FFFFFFFF"
android:textSize="16sp" />
<TextView
android:id="#+id/claim_status"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="#00000000"
android:gravity="end|center_vertical"
android:text=""
android:textColor="#FFFFFFFF"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:id="#+id/bottom_layout"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_weight="0.48"
android:background="#00000000"
android:orientation="horizontal" >
<TextView
android:id="#+id/claim_date"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:background="#00000000"
android:gravity="start|center_vertical"
android:text=""
android:textColor="#FFFFFFFF"
android:textSize="14sp" />
<TextView
android:id="#+id/claim_distance"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="50dp"
android:layout_marginStart="50dp"
android:layout_marginRight="50dp"
android:layout_marginEnd="50dp"
android:layout_weight="1.0"
android:layout_gravity="center"
android:background="#00000000"
android:gravity="center|center_vertical"
android:text=""
android:textSize="12sp"
android:textColor="#FFFFFFFF"/>
<TextView
android:id="#+id/claim_amount"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="#00000000"
android:gravity="end|center_vertical"
android:text=""
android:textColor="#FFFFFFFF"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<Button
android:id="#+id/claim_delete_in_list"
android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:text="#string/delete"
android:textSize="16sp"
android:textColor="#FFFFFFFF"
android:background="#android:color/holo_red_dark"
/>
</LinearLayout>

Android Null Pointer Exception ListFragment

I cannot figure out what to do to fix this Null Pointer Exception I am getting. mButton.setText("Hi"); is what triggers it. I have tried looking at other questions but I have not been able to get it to work. Here is my code:
ContactsTab.java
public class ContactsTab extends ListFragment implements LoaderCallbacks<Cursor> {
private CustomAdapter mAdapter;
private Cursor mCursor;
private String currentQuery;
private Button mButton;
private static final String[] PROJECTION = {
Contacts._ID,
Contacts.DISPLAY_NAME_PRIMARY,
Contacts.LOOKUP_KEY,
Contacts.PHOTO_THUMBNAIL_URI,
Contacts.HAS_PHONE_NUMBER,
};
private static final String[] FROM = { Contacts.DISPLAY_NAME_PRIMARY };
private static final int[] TO = { R.id.contact_text };
private static final String SELECTION = "(" + Contacts.IN_VISIBLE_GROUP + " = 1) AND (" + Contacts.HAS_PHONE_NUMBER + " != 0 )";
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
View v =inflater.inflate(R.layout.contacts_tab, container, false);
mButton = (Button) v.findViewById(R.id.badge);
mButton.setText("Hi");
return v;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCursor = null;
mAdapter = new CustomAdapter(getActivity(), R.layout.contacts_list_item, mCursor, FROM, TO, 0);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
getListView().setDivider(null);
getListView().setDividerHeight(0);
}
...
}
contacts_tab.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contacts_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
contacts_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:background="#color/white">
<Button
android:id="#+id/badge"
android:background="#drawable/circle_button"
android:fontFamily="sans-serif-thin"
android:textSize="24sp"
android:textColor="#color/white"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:gravity="center"/>
<TextView
android:id="#+id/contact_text"
android:layout_width="match_parent"
android:layout_height="64dp"
android:textColor="#color/grey_dark"
android:textSize="20sp"
android:fontFamily="sans-serif-thin"
android:gravity="center_vertical"/>
</LinearLayout>
By code
View v =inflater.inflate(R.layout.contacts_tab, container, false);
mButton = (Button) v.findViewById(R.id.badge);
mButton.setText("Hi");
you are trying to get Button, which is part of contacts_tab.xml, but in this xml you don't have any buttons.
You have button in your adapter list item and you need to get reference to that button using adapter.
You need to do this in your adapter, not in the fragment. In the adapter, you will have a reference to each one of the items of the listview.
In addition to #Anand Singh answer, using a ListFragment requires a specific layout with predefined ListView id:
ListFragment has a default layout that consists of a single list view. However, if you desire, you can customize the fragment layout by returning your own view hierarchy from onCreateView(LayoutInflater, ViewGroup, Bundle).
To do this, your view hierarchy must contain a ListView object with the id "#android:id/list" (or list if it's in code)
For more please look at ListFragment documentation.

Styling string in ListView, Android Dev

I am trying to style the resulting strings in a ListView.
I have a ListView layout, and the following onCreate method for the corresponding Activity.
private List<Address> addressList;
public class AddressesActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addresses);
AddressDBHandler datasource = new AddressDBHandler(this);
datasource.open();
List<Address> values = datasource.getAllAddresses();
MyAdapter adapter = new MyAdapter(this, android.R.layout.simple_list_item_1, addressList);
setListAdapter(adapter);
}
.
.
.
The following is my xml file:
<?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="vertical" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="51dp"
android:gravity="center"
android:textSize="20sp"
android:textStyle="bold"
android:text="#string/no_addresses" />
I was told to make the MyAdapter class as follows:
public class MyAdapter extends ArrayAdapter<Address> {
Context context;
int layoutResourceId;
public MyAdapter(Context context, int layoutResourceId, List<Address> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
StringHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new StringHolder();
holder.txtTitle = (TextView) row.findViewById(R.id.text1);
row.setTag(holder);
}
else
{
holder = (StringHolder)row.getTag();
}
Address addressItem = getItem(position);
Spanned format = Html.fromHtml("<br/><span color='red'>" + addressItem.getAddress() + "</span><br/>" + addressItem.getName() + "<br/>");
holder.txtTitle.setText(format);
return row;
}
static class StringHolder
{
TextView txtTitle;
}
My problem is in understanding :
holder.txtTitle = (TextView) row.findViewById(R.id.text1),
I am unsure what R.id.text1 is supposed to be.
I do have an additional question: Where are #android:id/empty and #android:id/list being referenced? Seems that they are default expectations from ArrayAdapter?
#android:id/empty and #android:id/list are predefined ids that are part of the android platform. ListActivities and ListFragments expect that these are present (or atleast that android:id/list is present) in the layout xml file. It means you don't have to bind these views from the xml yourself.
holder.txtTitle = (TextView) row.findViewById(R.id.text1)
The line above is basically finding a view in the xml file, and binding it to a variable for use in your activity (or in that case your list row).
The R.id.text1 is the id of the view in your layout. It's what you would set in the android:id field of your xml view.
e.g.
<TextView android:id="#+id/mytextview"
android:layout_width="match_parent"
android:layout_height="match_parent">
In the case of your code above, you don't have a custom row layout, you are using a layout that is part of the android sdk (android.R.layout.simple_list_item_1). This layout has a textview with the id android.R.id.text1.
So, if you want to customise your list row, create your own layout file. You can put 1 textview, or multiple views in the layout.
You will then need to add those views to your StringHolder class, and bind up the views like is already being done with holder.txtTitle.
Change the instantiation of the adapter to reference your custom layout:
new MyAdapter(this, R.layout.my_awesome_layout, addressList);
Edit: It would be a really good idea to have a read through this to familiarise yourself a little more with listviews.

Can't set multiple choice selection in ListView

I'm having problems with setting multiple choice selection in ListView. My ListView has contacts' names which are retrieved from the android phone.
I've followed examples on setting multiple choice but it didn't work out.
I've tried typing
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.contacts_list, c, columns, views);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
this.setListAdapter(adapter);
but I don't see the checkbox in the ListView.
And I've replaced R.layout.contacts_list with android.R.layout.simple_list_item_multiple_choice and it showed checkboxes but no names from the android phone's contacts.
Here are my codes:
contacts_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#color/light_goldenrod"
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="wrap_content"
android:layout_weight="1"
android:stackFromBottom="false"
android:transcriptMode="normal"
android:choiceMode="multipleChoice" >
</ListView>
<TextView
android:textColor="#color/dark_purple"
android:id="#+id/contactName"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
ContactsList.java
public class ContactsList extends ListActivity
{
final Context context = this;
Cursor cursor;
String[] buddiesList =
{"Kanak Priya",
"Joanne Liew",
"Michelle Lam",
"Teo Kin Hua",
"Melissa Haiting",
"David Yeo",
"Natasha Akhbar",
"Gillian Gan",
"Sonia",
"Ms Long",
"Joan Tang",
"Stephanie",
"Nur Ashiqin"
};
BuddyDBAdapter buddyDB = new BuddyDBAdapter(this);
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.contacts_list);
ListView list = getListView();
setListAdapter(new ArrayAdapter<String> (this, R.layout.contacts_list, R.id.contactName, buddiesList));
Uri allContacts = Uri.parse("content://contacts/people");
Cursor c = managedQuery(allContacts, null, null, null, null);
String[] columns = new String[] {ContactsContract.Contacts.DISPLAY_NAME};
int[] views = new int[] {R.id.contactName};
startManagingCursor(c);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.contacts_list, c, columns, views);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
this.setListAdapter(adapter);
/*if(cursor.getCount()<0)
{
Intent displayIntent = new Intent(Intent.ACTION_VIEW);
displayIntent.setData(Uri.parse("content://contacts/people"));
startActivity(displayIntent);
displayIntent = new Intent(Intent.ACTION_VIEW);
//displayIntent.setData(Uri.parse("content://contacts/people/"+id));
startActivity(displayIntent);
}
else
{
final AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("ALERT!");
alertDialog.setMessage("NO Name is Found! D:");
alertDialog.setIcon(R.drawable.warning);
alertDialog.setButton("OK", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
Intent backIntent = new Intent(context, ContactsList.class);
startActivity(backIntent);
}
});
alertDialog.show();
}*/
}
#Override
public void onListItemClick(ListView l, View v, int position, long id)
{
buddyDB.open();
long name_id;
super.onListItemClick(l, v, position, id);
Cursor c = ((SimpleCursorAdapter)l.getAdapter()).getCursor();
TextView contactName = (TextView) v.findViewById(R.id.contactName);
String NameValue = contactName.getText().toString();
name_id = buddyDB.insertNames(NameValue);
Toast.makeText(getBaseContext(),
"Selected: " + buddiesList[position], Toast.LENGTH_SHORT).show();
buddyDB.close();
Oh by the way, the
String[] buddiesList =
{"Kanak Priya",
"Joanne Liew",
"Michelle Lam",
"Teo Kin Hua",
"Melissa Haiting",
"David Yeo",
"Natasha Akhbar",
"Gillian Gan",
"Sonia",
"Ms Long",
"Joan Tang",
"Stephanie",
"Nur Ashiqin"
};
is for my Toast message.
I really need help with this. Any help will be appreciated. Examples will be greatly appreciated too.
Thanks
You may have two choices:
1 - Use default layout from Android resources (simple_list_item_multiple_choice)
you may replace this code:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.contacts_list, c, columns, views);
to:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_multiple_choice, c, columns, new int {android.R.id.text1});
2 - Create your new row layout contains your defined checkbox and handle it by your own.
contact_list.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#color/light_goldenrod"
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="wrap_content"
android:layout_weight="1"
android:stackFromBottom="false"
android:transcriptMode="normal"
android:choiceMode="multipleChoice" >
</ListView>
</LinearLayout>
contact_entry.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:textColor="#color/dark_purple"
android:id="#+id/contactName"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<CheckBox
android:id="#+id/contactCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:checked="false" />
</LinearLayout>
Add custom cursor adapter like this:
public class YourCursorAdapter extends CursorAdapter {
private Context mContext;
private Cursor mCurser;
public YourCursorAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, ContentResolver co) {
super(context, c);
mCurser = c;
mContext = context;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.contact_entry, parent, false);
bindView(v, mContext, cursor);
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView contactName= (TextView)view.findViewById(R.id.contactName);
contactName.setText(cursor.getString((mCurser
.getColumnIndexOrThrow(Contacts.Phones.DISPLAY_NAME))));
CheckBox contactCheckbox = (TextView)view.findViewById(R.id.contactCheckbox);
contactCheckbox.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Checkbox checkBox = (Checkbox) v.findViewById(R.id.contactCheckbox)
if (checkBox.isChecked())
checkBox.setChecked(false);
else
checkBox.setChecked(true);
}
});
}
in your ListActivity:
YourCursorAdapter adapter = new YourCursorAdapter(this,
null, c, null, null,null);
this.setListAdapter(adapter);

How to find a TextView programmatically on ListActivity

I have a ListActivity and I want to set programmatically the text of a TextView that is inside my layout, I need to do this to all my lines.
This TextView will show the Currency Simbol for the current Locale on each line of the ListActivity.
Code snippet:
DepositoRepository repo = new DepositoRepository(this);
Cursor c = repo.getCursor();
adapter = new SimpleCursorAdapter(this, R.layout.deposito_list, c,
new String[] { Deposito.COLUNA_VALOR, Deposito.COLUNA_DATA },
new int[] { R.id.tvValorDeposito, R.id.tvDataDeposito });
setListAdapter(adapter);
What I want for all rows:
Currency moeda = Currency.getInstance(Locale.getDefault());
TextView tvMoeda = (TextView)findViewById(R.id.tvMoeda);
tvMoeda.setText(moeda.getSymbol(Locale.getDefault()));
You can use a Custom Adapter to your listView. If you want I can edit my answer and show you how to do this. Here is something that can put you on a right track. Adapt this code to your application.
And from your activity just call setListAdapter(adapter), adapter being your custom adapter.
Hope this helps!
EDIT:
import java.util.Currency;
import java.util.Locale;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;
public class CustomAdapter extends CursorAdapter{
public CustomAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
Currency moeda = Currency.getInstance(Locale.getDefault());
TextView tvMoeda = (TextView)view.findViewById(R.your_id);//your textView id here
tvMoeda.setText(moeda.getSymbol(Locale.getDefault()));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.item, parent, false);//your layout here
bindView(v, context, cursor);
return v;
}
}
Simple example activity that displays a list of all internal music files (ringtones etc).
MyActivity.java
public class MyActivity extends Activity {
private MyCursorAdapter mAdapter;
// that's what we want to know from the database
private static final String[] PROJECTION = new String[] {
MediaStore.Audio.AudioColumns._ID, // 0 - _id must be present
MediaStore.Audio.AudioColumns.TITLE, // 1
MediaStore.Audio.AudioColumns.DATA // 2
};
// those from above - no need for cursor.getColumnIndex()
private static final int TITLE_IDX = 1;
private static final int TEXT_IDX = 2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView lv = (ListView) findViewById(R.id.list_view);
mAdapter = new MyCursorAdapter(this, TITLE_IDX, TEXT_IDX);
lv.setAdapter(mAdapter);
loadContent();
}
// would be better to do in a Loader, AsyncTask, ...
private void loadContent() {
ContentResolver cr = getContentResolver();
Cursor c = cr.query(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI,
PROJECTION, null, null, null
);
mAdapter.changeCursor(c);
}
}
MyCursorAdapter.java
there is no real dependency on the Cursor in this class, it's much like the SimpleCursorAdapter
public class MyCursorAdapter extends CursorAdapter {
private final LayoutInflater mInflater;
private final int mTitleIdx, mTextIdx;
/**
* Creates a new MyCursorAdapter. Set cursor via changeCursor / swapCursor
* #param context <code>this</code> will usually do
* #param titleColumnIdx cursor columnindex to be displayed as title
* #param textColumnIdx cursor columnindex to be displayed as text below
*/
public MyCursorAdapter(Context context, int titleColumnIdx, int textColumnIdx) {
super(context, null, false);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTitleIdx = titleColumnIdx;
mTextIdx = textColumnIdx;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.title);
TextView text = (TextView) view.findViewById(R.id.text);
title.setText(cursor.getString(mTitleIdx));
text.setText(cursor.getString(mTextIdx));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View item = mInflater.inflate(R.layout.list_item, null);
// could do static init here / attach holder / set onClickListeners, ...
return item;
}
}
main.xml
<?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" >
<ListView
android:id="#+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<!-- Preview: listitem=#layout/list_item -->
</ListView>
</LinearLayout>
list_item.xml
<?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" >
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="#android:style/TextAppearance.Large"
android:textColor="#android:color/primary_text_dark"
android:layout_marginTop="5dp" />
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="#android:style/TextAppearance.Small"
android:textColor="#android:color/secondary_text_dark"
android:singleLine="true"
android:ellipsize="end"
android:layout_marginBottom="5dp" />
</LinearLayout>
What you get

Categories