Can't figure out how to dynamically change custom listview - android

I have a custom listview. when te listview is called i want it to load all the profiles from my database, this works. but i also want to check the status of the profile and depending of the result i want to show a certain icon next to it. but i cant seem to figure out how to get this done properly.. this is what i have so far:
profiles_list.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/colorAccent">
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_marginBottom="10dp"
android:layout_above="#+id/menuBtn"
android:background="#2cffffff">
</ListView>
<RelativeLayout/>
list_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TableRow>
<ImageView
android:id="#+id/statusIcon"
android:layout_width="50dp"
android:layout_height="50dp"/>
<TextView
android:id="#+id/profile"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="10dp"/>
</TableRow>
</TableLayout>
MainActivity.class
public class ProfilesList extends CredenceOneActivity implements AdapterView.OnItemClickListener {
static final int STATUS_SUCCES =1;
static final int STATUS_WARNING =2;
static final int STATUS_ERROR =3;
private ListView list;
private ArrayAdapter<String> adapter;
private ArrayList<String> arrayList;
private DB_Handler db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
setContentView(R.layout.profiles_list);
}
list = (ListView) findViewById(R.id.listView);
arrayList = new ArrayList<String>();
try {
db = new DB_Handler(this);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item, arrayList);
// Here, you set the data in your ListView
list.setAdapter(adapter);
list.setOnItemClickListener(this);
loadRegisteredProfiles();
}
public void loadRegisteredProfiles() {
List<DB_Profiles> storedProfiles = db.getAllProfiles();
for (DB_Profiles profile : storedProfiles) {
String name= profile.getNAME();
arrayList.add(name);
adapter.notifyDataSetChanged();
}
i want to do something like this for each profile that is loaded in the listview:
DB_Profiles profile;
if (profile.getStatus==STATUS_SUCCES{
statusIcon.setImageResource(R.drawable.succes);}
else{profile.getStatus==STATUS_ERROR{
statusIcon.setImageResource(R.drawable.error);}}
}
any advice would be greatly appreciated!

In the getView() of your Custom Adapter write the below piece of code.
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.rowLayout, null);
holder = new ViewHolder();
holder.imagView = (ImageView) convertView.findViewById(R.id.img);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (profile.getStatus==STATUS_SUCCES)
{
holder.imagView.setImageResource(R.drawable.succes);
}
else if(profile.getStatus==STATUS_ERROR)
{
holder.imagView.setImageResource(R.drawable.error);
}
return convertView;
And declare static inner class in your custom adapter, like this
static class ViewHolder {
ImageView img;
}

In the getView() of the listview's adapter, you can use the setImageResource() of the imageView, in your list_item layout.

Related

String Array With Custom Adapters

Can we use String array with custom adapter and data should be display in Listview?
I mean something like that
String [] s= {"cars","bike","train"};
Now how this string array will attach with Custom adapter and how data will show in the ListView.
I know this is easy with ArrayList.
But I want to do it with simple String Array.
Well, you can use a custom adapter for that. But you could also use the ArrayAdapter class if you just want to show text on your ListView.
But, if for whatever reason you want to create a custom adapter, try the following...
In this particular case I'm subclassing the BaseAdapter class.
This custom adapter will take hold of my data model, and will inflate the data to my ListView rows.
First, I'll create the XML of my custom row. You can see the code below.
item.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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test text"
android:id="#+id/tv"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"/>
</RelativeLayout>
Here I've created a row that displays a text.
Now, I'll create my custom adapter to handle this XML. As you can see below.
MyAdapter.java
public class MyAdapter extends BaseAdapter {
private static final String LOG_TAG = MyAdapter.class.getSimpleName();
private Context context_;
private ArrayList<String> items;
public MyAdapter(Context context, ArrayList<String> items) {
this.context_ = context;
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context_.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.item_mail, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.tv);
String text = items.get(position);
Log.d(LOG_TAG,"Text: " + text);
tv.setText(text);
return convertView;
}
}
Ok. Now we have everything to make this work. In your Activity class, do something like that:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:text="#string/hello_world"
android:id="#+id/tv_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tv_header">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add item"
android:id="#+id/button"
android:layout_gravity="center" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView" />
</LinearLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends ActionBarActivity {
private int numItem = 1; // Dummy int to create my items with different numbers.
private MyAdapter myAdapter; // Your custom adapter.
private ArrayList<String> items; // This is going to be your data structure, every time you change it, call the notifyDataSetChanged() method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.button);
ListView lv = (ListView) findViewById(R.id.listView);
items = new ArrayList<>();
myAdapter = new MyAdapter(this,items);
lv.setAdapter(myAdapter);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addItem(); // The method I'm using to insert the item. Look for it below.
}
});
}
private void addItem() {
items.add("Text " + numItem++);
mailAdapter.notifyDataSetChanged(); // Notifying the adapter that my ArrayList was modified.
}
}
This should do the trick.
From what you told me, you want to use a String array instead of a ArrayList<String>. Well, change the adapter to the following.
MyAdapter.java
public class MyAdapter extends BaseAdapter {
private static final String LOG_TAG = MyAdapter.class.getSimpleName();
private Context context_;
private String[] items;
public MyAdapter(Context context, String[] items) {
this.context_ = context;
this.items = items;
}
#Override
public int getCount() {
return items.length;
}
#Override
public Object getItem(int position) {
return items[position];
}
#Override
public long getItemId(int position) {
return position;
}
// Rest of the code... Same as before.
}
MainActivity.java
public class MainActivity extends ActionBarActivity {
private MyAdapter myAdapter; // Your custom adapter.
private String[] items;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.button);
ListView lv = (ListView) findViewById(R.id.listView);
items = {"Whatever","String","You","Like"};
myAdapter = new MyAdapter(this,items);
lv.setAdapter(myAdapter);
}
}
The problem with this approach: Your adapter will have a fixed size, which will be the size of your String array once you create it. And you won't be able to make it bigger, unless you create another adapter with a different String array.
This question discusses this matter.

ListView updated from EditText

I have a Custom Listview that it is updated from a EditText component in a dialog. I have the custom row, the adapter class and the custom dialog all working but I can't seem to trigger the code in the adatper class that would add the text from the edit text control to the list. Here is my activity code, let me know if you want the adapter code. It worked before I added the custom row and adapter to the list :(
Symptom of problem: emailAdapter.notifyDataSetChanged(); does nothing
public class InvitePlayers_Activity extends Activity {
ListViewAdapter emailAdapter = null;
ImageView imgView_mail;
ImageView imgView_confirm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE); //remove title bar
setContentView(R.layout.activity_inviteplayers);
//Generate list View from ArrayList
displayListView();
}
private void displayListView() {
//assign controls
final ListView listView = (ListView) findViewById(R.id.listView_invitePlayers);
imgView_mail = (ImageView)findViewById(R.id.imgView_mail);
//Test data
ArrayList<String> inviteNew = new ArrayList<String>();
final ArrayList<ArrayList<String>> inviteList = new ArrayList<ArrayList<String>>();
emailAdapter = new ListViewAdapter(this,inviteList);
listView.setAdapter(emailAdapter);
// Assign adapter to ListView
listView.setTextFilterEnabled(true);
//Edit listeners
imgView_mail.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
//variables
final String enteredMail = "testListViewEntry";
final ArrayList<ArrayList<String>> inviteList = new ArrayList<ArrayList<String>>();
ArrayList<String> invite = new ArrayList<String>();
invite.add(0, enteredMail);//add first email
invite.add(1,"icon_invitestatussent.png"); //add first status icon
inviteList.add(invite);
emailAdapter.notifyDataSetChanged();
listView.setAdapter(emailAdapter);
}
});
}
}
Adapter code as requested
public class ListViewAdapter extends BaseAdapter {
private Activity context;
ArrayList<ArrayList<String>> inviteDetails = new ArrayList<ArrayList<String>>();
public ListViewAdapter(Activity context, ArrayList<ArrayList<String>> inviteDetails ) {
this.inviteDetails = inviteDetails;
this.context = context;
}
#Override
public int getCount() {
return inviteDetails.size();
}
#Override
public Object getItem(int i) {
return inviteDetails.get(i).get(0);
}
#Override
public long getItemId(int i) {
return i;
}
public View getView(int position, View view, ViewGroup parent){
//Inflater
LayoutInflater inflater = context.getLayoutInflater();
//get row view
if (view == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
view = mInflater.inflate(R.layout.list_item_email, null);
}
//assign controls
final TextView textView_playerEmail = (TextView) view.findViewById(R.id.textView_playerEmail);
ImageView imgView_inviteStatus = (ImageView) view.findViewById(R.id.imgView_inviteStatus);
//Assign control values that are dynamic
textView_playerEmail.setText(inviteDetails.get(position).get(0));
imgView_inviteStatus.setImageResource(R.drawable.icon_invitestatussent);
return view;
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
Custom row xml
<?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="fill_parent">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp"
android:id="#+id/textView_playerEmail"
android:textColor="#color/white"
android:text="item1">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgView_inviteStatus" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgView_remove"
android:src="#drawable/btn_cancel" />
</LinearLayout>
The activity layout
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="20"
android:background="#color/yellow"
android:layout_margin="20dp"
android:padding="5dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="1"
android:gravity="left|center">
<ImageView
android:layout_width="45dp"
android:layout_height="34dp"
android:id="#+id/imgView_mail"
android:src="#drawable/btn_mail"
android:layout_weight="0.22"
android:padding="3dp" />
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listView_invitePlayers"
android:layout_gravity="center_horizontal" />
</LinearLayout>
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="#+id/btn_confirm"
android:src="#drawable/btn_confirm"
android:clickable="false"
android:adjustViewBounds="true"
android:layout_gravity="center_horizontal"
android:padding="2dp"
android:layout_weight="1" />
</LinearLayout>
</FrameLayout>
Well, for what we discussed, you wanted something like this:
When you want to make a custom ListView, you have to write your own adapter. In this particular case I'm subclassing the BaseAdapter class.
This custom adapter will take hold of my data model, and will inflate the data to my ListView rows.
First, I'll create the XML of my custom row. You can see the code below.
item_mail.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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test text"
android:id="#+id/tv_mail"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/iv_icon"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#android:drawable/ic_menu_report_image" />
</RelativeLayout>
Here I've created a row that displays a text and an image.
Now, I'll create my custom adapter to handle this XML. As you can see below.
MailAdapter.java
public class MailAdapter extends BaseAdapter {
private static final String LOG_TAG = MailAdapter.class.getSimpleName();
private Context context_;
private ArrayList<ArrayList<String>> mailitems;
public MailAdapter(Context context, ArrayList<ArrayList<String>> mailitems) {
this.context_ = context;
this.mailitems = mailitems;
}
#Override
public int getCount() {
return mailitems.size();
}
#Override
public Object getItem(int position) {
return mailitems.get(position).get(0);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context_.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.item_mail, null);
}
TextView tv_mail = (TextView) convertView.findViewById(R.id.tv_mail);
ImageView iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon);
String mail = mailitems.get(position).get(0);
String icon = mailitems.get(position).get(1);
Log.d(LOG_TAG,"Mail: " + mail + " mail_icon: " + icon);
tv_mail.setText(mail);
// iv_icon.setImageURI(); Here you can do whatever logic you want to update your image, using URI's, ID's, or something else.
return convertView;
}
}
Ok. Now we have everything to make this work. In your Activity class, do something like that:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:text="#string/hello_world"
android:id="#+id/tv_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tv_header">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add mail"
android:id="#+id/button"
android:layout_gravity="center" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView" />
</LinearLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends ActionBarActivity {
private int numMail = 1; // Dummy int to create my items with different numbers.
private MailAdapter mailAdapter; // Your custom adapter.
private ArrayList<ArrayList<String>> mailItems; // This is going to be your data structure, everytime you change it, call the notifyDataSetChanged() method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.button);
ListView lv_mail = (ListView) findViewById(R.id.listView);
mailItems = new ArrayList<>();
mailAdapter = new MailAdapter(this,mailItems);
lv_mail.setAdapter(mailAdapter);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addItem(); // The method I'm using to insert the item. Look for it below.
}
});
}
// Here I'm creating a new ArrayList, and appending it to my 'mailItems' Array. After that, I'm notifying the adapter that my data changed.
private void addItem() {
ArrayList<String> mail = new ArrayList<>();
mail.add(0,"mail " + numMail++);
mail.add(1,"path_to_image"); // Depending on what you want to do, put your path, URI, or whatever other way you want to store that image data.
mailItems.add(mail); // Inserting the data on the ArrayList.
mailAdapter.notifyDataSetChanged(); // Notifying the adapter that my ArrayList was modified.
}
}
This should do the trick.
I guess your problem was that you weren't updating the same ArrayList that was in your custom adapter. That's why when you called notifyDataSetChanged()nothing happened, I mean. You were creating a new ArrayList, which wasn't the same that was in your adapter. So here's what I did... I've made the ArrayList global, and then I've used it in my custom adapter constructor. After that, when the user triggers the onClick() method of my button, I'm inserting some new data on my global Array, and then I'm notifying the adapter that the data changed.
You can read a little more about that here and I've found a similar question here, which you can read as well.
Edit: Another related question, which might be an interesting read.

Can't find TextView in recursive custom Listview adapter

I created this class called GeoArea, which is suppose to store "Geographical Area" that have children Geographical Areas, this is fairly strait foward:
public class GeoArea {
public String id;
public String name;
public List<GeoArea> subGeoAreas;
public GeoArea parentGeoArea;
public GeoArea(String id) {
this.id = id;
name = id;
subGeoAreas = new LinkedList<GeoArea>();
}
#Override
public String toString() {
return name;
}
}
I have created the following Layout to render it on Android, the idea here is to for each GeoArea to recursively render it self and then it's children GeoArea in a listView:
//layout_geo_area.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/txtGeoAreaName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:gravity="left"
android:text="Geo Area Name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ListView
android:id="#+id/listViewChildGeoAreas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/txtGeoAreaName"
android:gravity="left" >
</ListView>
</RelativeLayout>
This is my adapter I created for GeoArea to be displayed in a listView:
public class AdapterGeoArea extends ArrayAdapter<GeoArea>{
private ArrayList<GeoArea> _myGeoArea;
private Context _myContext;
LayoutInflater _inflater;
public AdapterGeoArea(Context context, ArrayList<GeoArea> myGeoArea) {
super(context, 0, myGeoArea);
_myGeoArea = myGeoArea;
_inflater = LayoutInflater.from(context);
_myContext = context;
}
public int getCount() {
return _myGeoArea.size();
}
public View getView(int position, View convertView, ViewGroup parent) {
GeoAreaLayoutHolder holder;
if (convertView == null) {
convertView = _inflater.inflate(R.layout.layout_geo_area,parent,false);
holder = new GeoAreaLayoutHolder();
holder.txtGeoAreaName = (TextView)convertView.findViewById(R.id.txtGeoAreaName);
holder.txtGeoAreaName.setTag(convertView);
holder.listViewChildGeoAreas = (ListView)convertView.findViewById(R.id.listViewChildGeoAreas);
holder.listViewChildGeoAreas.setTag(convertView);
} else {
holder = (GeoAreaLayoutHolder) convertView.getTag();
}
GeoArea curGeoArea = _myGeoArea.get(position);
holder.txtGeoAreaName.setText(curGeoArea.name);
if(curGeoArea.subGeoAreas.size()>0){
ArrayList<GeoArea> testList = new ArrayList<GeoArea>();
AdapterGeoArea adapter = new AdapterGeoArea(_myContext, testList);
for(GeoArea childGeoArea:curGeoArea.subGeoAreas){
testList.add(childGeoArea);
}
holder.listViewChildGeoAreas.setAdapter(adapter);
}
return convertView;
}
static class GeoAreaLayoutHolder {
public TextView txtGeoAreaName;
public ListView listViewChildGeoAreas;
}
}
And here is my Activity that I am using to set it all up:
public class ActivityGeoAreas extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_geo_area);
GeoArea.searchTerm = "Bar & Grill";
GeoArea torontoArea = new GeoArea("cityOfToronto");
ArrayList<GeoArea> testList = new ArrayList<GeoArea>();
testList.add(torontoArea);
AdapterGeoArea adapter = new AdapterGeoArea(this, testList);
ListView lv = (ListView) findViewById(R.id.listViewChildGeoAreas);
lv.setAdapter(adapter);
}
}
When I try to run it, I get the error nullPointerException on the line:
holder.txtGeoAreaName.setText(curGeoArea.name);
What am I doing wrong?
You may want to check ExpandableListView may suit your needs better
http://developer.android.com/reference/android/widget/ExpandableListView.html
An example # http://www.androidhive.info/2013/07/android-expandable-list-view-tutorial/
Continuing from my previous answer to your question ( i though that solved your problem)
To display just name in your listview
list_row.xml // this is the layout with textview to be inflated in getView.
Each row will have textview
<?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" >
<TextView
android:id="#+id/textGeoArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="14dp"
android:text="Choose Area"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
layout_geo_area.xml // with only listview no textview
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/listViewChildGeoAreas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:gravity="left" >
</ListView>
</RelativeLayout>
Now your adapter class
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_row,parent,false);
// inflate list_row.xml with textview
holder = new ViewHolder();
holder.tv = (TextView)convertView.findViewById(R.id.textGeoArea);
holder.setTag(convertView);
}
else {
holder = (ViewHolder) convertView.getTag();
}
GeoArea curGeoArea = _myGeoArea.get(position);
holder.tv.setText(curGeoArea.name);
return convertView;
}
static class ViewHolder // use a view holder for smooth scrolling an performance
{
TextView tv;
}
You have a custom adapter.
public class AdapterGeoArea extends ArrayAdapter<GeoArea>{
Now you set the adapter to listview like below
AdapterGeoArea adapter = new AdapterGeoArea(this, testList);
ListView lv = (ListView) findViewById(R.id.listViewChildGeoAreas);
lv.setAdapter(adapter);
So why do you need the below. remove these
if(curGeoArea.subGeoAreas.size()>0){
ArrayList<GeoArea> testList = new ArrayList<GeoArea>();
AdapterGeoArea adapter = new AdapterGeoArea(_myContext, testList);
for(GeoArea childGeoArea:curGeoArea.subGeoAreas){
testList.add(childGeoArea);
}
holder.listViewChildGeoAreas.setAdapter(adapter);

Android - ListView refresh/update from the Main Activity where it is called

I have an application that lists the values of a product by Variant, Unit, and Quantity.
I have an activity where the ListView is shown:
public class OrderForm extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_form);
ArrayList image_details = getListData();
final ListView lv1 = (ListView) findViewById(R.id.custom_list);
lv1.setAdapter(new CustomListAdapter(this, image_details));
}
private ArrayList getListData() {
ArrayList results = new ArrayList();
OrderDetailsClass orderData = new OrderDetailsClass();
return results;
}
public void onAddItem(View view){
ArrayList results = new ArrayList();
OrderDetailsClass orderData = new OrderDetailsClass();
orderData = new OrderDetailsClass();
orderData.setVariants("Flavored");
orderData.setUnit("cans");
orderData.setQuantity(1);
results.add(orderData);
//selectVariant();
//selectUnit();
//selectQuantity();
}
}
This is my CustomAdapter
public class CustomListAdapter extends BaseAdapter {
private ArrayList<OrderDetailsClass> listData;
private LayoutInflater layoutInflater;
public CustomListAdapter(Context context, ArrayList<OrderDetailsClass> listData) {
this.listData = listData;
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.list_row_layout, null);
holder = new ViewHolder();
holder.variantView = (TextView) convertView.findViewById(R.id.variant);
holder.unitView = (TextView) convertView.findViewById(R.id.unit);
holder.quantityView = (TextView) convertView.findViewById(R.id.quantity);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.variantView.setText(listData.get(position).getVariants());
holder.unitView.setText("By, " + listData.get(position).getUnit());
holder.quantityView.setText(String.valueOf(listData.get(position).getQuantity()));
return convertView;
}
static class ViewHolder {
TextView variantView;
TextView unitView;
TextView quantityView;
}
public void updateResults(ArrayList<OrderDetailsClass> results) {
listData = results;
//Triggers the list update
notifyDataSetChanged();
}
}
This is list_row_layout
<?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:minHeight="50dp"
android:orientation="horizontal"
android:padding="5dip"
-->
<TextView
android:id="#+id/variant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="variant" />
<TextView
android:id="#+id/unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="unit" />
<TextView
android:id="#+id/quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="quantity" />
</RelativeLayout>
This is the activity_order_form
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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/custom_list"
android:layout_width="fill_parent"
android:layout_height="386dp"
android:dividerHeight="1dp" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:onClick="onAddItem"
android:text="Add" />
</RelativeLayout>
What I want to do is that when I press the onAddItem function, after the data has been added, the ListView will refresh and display the changes. So far, what I've seen is that notifyDataSetChanged() being used in the BaseAdapter class. I've tried it but it seems that notifyDataSetChanged() should be called within BaseAdapter, I want to be able to refresh from my OrderForm activity.
Any ideas?
Thanks.
Keep a reference to your CustomAdapter in OrderForm activity:
public class OrderForm extends Activity {
CustomListAdapter customListAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_form);
ArrayList image_details = getListData();
final ListView lv1 = (ListView) findViewById(R.id.custom_list);
customListAdapter = new CustomListAdapter(this, image_details);
lv1.setAdapter(customListAdapter);
}
Then you can call customAdapter.notifyDataSetChanged(). This is a public method on the adapter so you can call it from the activity just fine.

Use array adapter with more views in row in listview

I have stumbled upon a problem I can't quite get my head around, so I was hoping perhaps someone here have had the same problem or knew a good way of solving the problem.
I have created a view containing a ListView. This ListView contains two TextView.
The problem is that I don't know where I send the values which are meant to go in the second text view using the ArrayAdapter. Is there a way to send with more information to the ArrayAdapter so that I can feed the "todaysmenu" TextView?
The ArrayAdapter method:
private void createList() {
ListView lv = (ListView) findViewById(R.id.mylist);
String[] values = new String[] { "Android", "Linux", "OSX",
"WebOS", "Windows7", "Ubuntu", "OS/2"
};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.rowlayout, R.id.restaurantname, values);
lv.setAdapter(adapter);
}
The row markup:
<?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="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/restaurantname"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#+id/todaysmenu" />
</LinearLayout>
The activity layout:
<?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/mylist"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
At the beginning I got everything to work, but when I added the second textfield problems arouse. In advance, thank you for your help!
To achieve this you have to build a custom adapter and inflate your custom row layout. Using ArrayAdapter won't work because
By default this class expects that the provided resource id references
a single TextView. If you want to use a more complex layout, use the constructors that also takes a field id. That field id should reference a TextView in the larger layout resource.
So, your custom adapter class could be somthing like:
public class CustomAdapter extends ArrayAdapter {
private final Activity activity;
private final List list;
public CustomAdapter(Activity activity, ArrayList<Restaurants> list) {
this.activity = activity;
this.list = list;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
ViewHolder view;
if(rowView == null)
{
// Get a new instance of the row layout view
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.rowlayout, null);
// Hold the view objects in an object, that way the don't need to be "re- finded"
view = new ViewHolder();
view.retaurant_name= (TextView) rowView.findViewById(R.id.restaurantname);
view.restaurant_address= (TextView) rowView.findViewById(R.id.textView1);
rowView.setTag(view);
} else {
view = (ViewHolder) rowView.getTag();
}
/** Set data to your Views. */
Restaurants item = list.get(position);
view.retaurant_name.setText(item.getTickerSymbol());
view.restaurant_address.setText(item.getQuote().toString());
return rowView;
}
protected static class ViewHolder{
protected TextView retaurant_name;
protected TextView restaurant_address;
}
}
And your Restaurant.java class could as simple as I describe below:
public class Restaurants {
private String name;
private String address;
public Restaurants(String name, String address) {
this.name = name;
this.address = address;
}
public void setName(String name) {
this.name= name;
}
public String getName() {
return name;
}
public void setAddress(String address) {
this.address= address;
}
public String getAddress() {
return address;
}
}
Now, in you main activity just bind you list with some data, like;
/** Declare and initialize list of Restaurants. */
ArrayList<Restaurants> list = new ArrayList<Restaurants>();
/** Add some restaurants to the list. */
list.add(new Restaurant("name1", "address1"));
list.add(new Restaurant("name2", "address2"));
list.add(new Restaurant("name3", "address3"));
list.add(new Restaurant("name4", "address4"));
list.add(new Restaurant("name5", "address5"));
list.add(new Restaurant("name6", "address6"));
At this point you're able to set the custom adapter to your list
ListView lv = (ListView) findViewById(R.id.mylist);
CustomAdapter adapter = new CustomAdapter(YourMainActivityName.this, list);
lv.setAdapter(adapter);
This is all and it should work nicelly, but I strongly recommend you to google for some better alternatives to implement others Adapters.
You could try this https://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/. You have to create a custom class Item with fields you need and extend ArrayAdapter .
I think that your problem is here:
Instead of this:
<?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="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/restaurantname"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#+id/todaysmenu" />
</LinearLayout>
Try something like this:
<?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="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test text"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test text" />
</LinearLayout>
If that works, then place your text in the /res/val/string folder like so:
<string name="testText">Put your text here...</string>
and then call like this:
<?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="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/testText"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/testText" />
</LinearLayout>
You would then set the dynamic values like this:
TextView tv = (TextView)findViewById(R.id.restaurantname);
tv.setText(values);
I had to solve the same problem and tried to use the arrayadapter as answered here above, but it didn't work.
Later I succeeded to do it with baseadapter -- this is the adapter:
public class BusinessAdapter2 extends BaseAdapter {
private final ArrayList<Business> myList;
LayoutInflater inflater;
Context context;
public BusinessAdapter2(Context context, ArrayList<Business> myList) {
this.myList = myList;
this.context = context;
inflater = LayoutInflater.from(this.context);
}
#Override
public int getCount() {
return myList.size();
}
#Override
public Object getItem(int position) {
return myList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null) convertView = inflater.inflate(R.layout.business_list_item_2, parent, false);
// assign the view we are converting to a local variable
View v = convertView;
Business b = myList.get(position);
if (b != null) {
TextView name = (TextView) v.findViewById(R.id.textview_name);
TextView address = (TextView) v.findViewById(R.id.textview_address);
TextView description = (TextView) v.findViewById(R.id.textview_description);
TextView discount = (TextView) v.findViewById(R.id.textview_discount);
// check to see if each individual textview is null.
// if not, assign some text!
if (name != null){
name.setText(b.name);
}
if (address != null){
address.setText(b.address);
}
if (description != null){
description.setText(b.description);
}
if (discount != null){
discount.setText(b.discountRate);
}
}
// the view must be returned to our activity
return v;
}
}
this is the Object class I used (Business):
public class Business {
String name,address,description,discountRate;
public Business(){}
public Business(String name,String address,String description,String discountRate){
this.name=name;
this.address=address;
this.description=description;
this.discountRate=discountRate;
}
}
and this is how I populate the listview into the adapter:
ArrayList<Business> businesses2=new ArrayList<Business>(Arrays.asList(for_listview_objects));
adapter_objects =new BusinessAdapter2(
context, // The current context (this activity)
businesses2);
listView.setAdapter(adapter_objects);

Categories

Resources