CustomListAdapter with custom ArrayList in Android - android

CustomListAdapter Class:
its like example for problem;
public class CustomList extends ArrayAdapter<String>{
private final Activity context;
private final List<FixtureData> list;
public CustomList(Activity context,List<FixtureData>list) {
super(context, R.layout.list_single);
this.context = context;
this.list = list;
}
#Override
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_single, null, true);
TextView txt_date = (TextView) rowView.findViewById(R.id.txt_date);
TextView txt_team1 = (TextView) rowView.findViewById(R.id.txt_team2);
TextView txt_team2 = (TextView) rowView.findViewById(R.id.txt_team1);
txt_date.setText(list.get(position).date.toString());
txt_team1.setText(list.get(position).team1.toString());
txt_team2.setText(list.get(position).team2.toString());
return rowView;
}
}
MainActivity Class:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
public List<FixtureData> fixtureArray = new ArrayList<FixtureData>();
class FixtureData extends Object{
public String date=null;
public String team1=null;
public String team2=null;
}
FixtureData fixture = new FixtureData();
fixture.date="1990";
fixture.team1="Manchester";
fixture.team2="Barcelona";
fixtureArray.add(fixture);
final CustomList adapter2 = new CustomList(MainActivity.this, fixtureArray);
liste=(ListView)findViewById(R.id.list1));
liste.setAdapter(adapter2);
liste.setItemsCanFocus(true);
liste.setFocusable(false);
liste.setFocusableInTouchMode(false);
liste.setClickable(false);
}}
its just example for problem, dont check intention.
When i use single ArrayList my Codes Working like;
final List<String> date = new ArrayList<String>();
final List<Integer> team1= new ArrayList<String>();
final List<Integer> team2= new ArrayList<String>();
but when i tried custom ArrayList like this, its not working
public List<FixtureData> fixtureArray = new ArrayList<FixtureData>();
class FixtureData extends Object{
public String date=null;
public String team1=null;
public String team2=null;
}
FixtureData fixture = new FixtureData();
fixture.date="1990";
fixture.team1="Manchester";
fixture.team2="Barcelona";
fixtureArray.add(fixture);
with this codes giving me null ListView,
How can i solve my problem?

Override the getCount method in your CustomList
#Override
public int getCount()
{
return list.size();
}
OR
change
super(context, R.layout.list_single);
to
super(context, R.layout.list_single,list);

Your first line of Program shows
public class CustomList extends ArrayAdapter< String >{
It should be :
public class CustomList extends ArrayAdapter< FixtureData >{
Your ListAdapter class should know about what type of Object its going to handle

It looks like there's a lot going on in your code, but in addition to what Brijesh mentioned about changing ArrayAdapter to ArrayAdapter, one other thing that seems to be happening is that you never set your list to your adapter. You send in your list, and call super(context, R.layout.list_single), but you didn't include your list in that call and don't separately set it later. In addition, although this is not the only way to deal with this issue, since you are using a custom list item view with multiple text views, it might be easier to just send a 0 as a placeholder for the layout resource - that's okay bc you define it later in getView(). The super constructor for ArrayAdapter expects a layout with one text view. You probably want to check out the android developer reference page for ArrayAdapter http://developer.android.com/reference/android/widget/ArrayAdapter.html so you can see what your options are and what is expected, but one option would be to just call super(context,0,list). BTW - if you want to use this.list, make sure to define it before you use it in the call to super, instead of after as you currently have it.

Related

notifyDataSetChanged() not working on custom RecyclerView adapter

I was trying to create a recyclerView that shows a list of current statusbar notifications . I have created a custom adapter (NotiRecyclerAdapter) that takes a List of NotificationItemInformation
public class NotificationItemInformation
{
int iconId,noitId;
String packageName;
Drawable notiIcon;
}
I am using an SQLite DB to store all the notifications.
The NotificationListenerService writes and deletes from the DB whenever a notification is posted or removed.
I use a method called
public List<NotificationItemInformation> ReadNotilist (Context context);
( which is inside myDBHelper ) to read the contents of the DB to a List of NotificationItemInformation called data (which is global,public and static in my Main Activity ) .
then I use adapter (which is also global,public and static in my Main Activity ) to take the data and set it to the RecyclerView inside the onCreate method of my MainActivity.
So far everything is working well. and i can see the RecyclerView populated with the current StatusBar notification.
The problem is that the list does not update (if a new notification comes) till i restart the activity . I tried calling...
MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this); // dbh is DBhelper object
MainActivity.adapter.notifyDataSetChanged();
...inside onNotificationPosted (after the adding into DB) of my NotificationListenerService . But still the RecyclerView is not getting updated till I restart the activity.
Here is my MainActivity if you want to take a look.
public class MainActivity extends AppCompatActivity
{
SQLiteDatabase db;
DBHelper dbh;
RecyclerView notificationIconRecyclerView;
public static NotiRecyclerAdapter adapter;
public static List<NotificationItemInformation> data = Collections.EMPTY_LIST;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbh = new DBHelper(this);
db = dbh.getDb();
notificationIconRecyclerView = (RecyclerView) findViewById(R.id.notificationIconRecyclerView);
data = dbh.ReadNotilist(this);
adapter = new NotiRecyclerAdapter(this,data);
notificationIconRecyclerView.setAdapter(adapter);
notificationIconRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,true));
}
}
Here is my custom Adapter for the RecyclerView
public class NotiRecyclerAdapter extends RecyclerView.Adapter<NotiRecyclerAdapter.MyViewHolder>
{
private LayoutInflater inflater;
List<NotificationItemInformation> data = Collections.emptyList();
NotiRecyclerAdapter(Context context, List<NotificationItemInformation> data)
{
inflater = LayoutInflater.from(context);
this.data = data;
}
#Override
public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer)
{
super.registerAdapterDataObserver(observer);
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = inflater.inflate(R.layout.custom_recyclerview_item,parent,false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
NotificationItemInformation current = data.get(position);
holder.recyclerItemIcon.setImageDrawable(current.notiIcon);
}
#Override
public int getItemCount()
{
return data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder
{
ImageView recyclerItemIcon;
public MyViewHolder(View itemView)
{
super(itemView);
recyclerItemIcon = itemView.findViewById(R.id.notiRecyclerItemIcon);
}
}
}
Do not reset the reference to the data object. Instead try something like this:
MainActivity.data.clear();
MainActivity.data.addAll(dbh.ReadNotilist(this));
MainActivity.adapter.notifyDataSetChanged();
In your adapter's constructor, you write
this.data = data;
This assigns the List<NotificationItemInformation> passed to the constructor to your adapter's data field. Your adapter is constructed like this:
adapter = new NotiRecyclerAdapter(this,data);
This means that your MainActivity.data field and your adapter.data field are both referring to the same list.
Later you write:
MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this);
MainActivity.adapter.notifyDataSetChanged();
The first line clears MainActivity.data and adapter.data (remember, they're the same list due to the way the adapter was constructed). The second line assigns a new list to MainActivity.data, but does not affect adapter.data in any way. The third line notifies the adapter that the data set has changed (which it has; it has been cleared), but your adapter won't "see" the new info from dbh.ReadNotilist().
AChez9's answer works because using addAll() instead of assignment (=) means that MainActivity.data and adapter.data are still pointing to the same List, so the adapter will "see" the new info.
This is why it is often correct to create copies of lists when you accept them from an outside source. In other words, your adapter's constructor might want to do this:
this.data = new ArrayList<>(data);
This will mean that it is "safe" from changes to the list passed to it (in this case, MainActivity.data). But this means you also need to expose a way for your activity to update your adapter correctly. I'd recommend a method like this:
public void updateData(List< NotificationItemInformation> data) {
this.data = new ArrayList<>(data);
notifyDataSetChanged();
}

Listview not updating after arraylist is updated?

I've seen many other posts in this context, but none helped. Problem is when i click on the addField button, the listview inside dialog adds new view just once. But at other clicks it doesn't get updated though The adapter works correctly (I mean the getView is called and also the arrayList in the adapter is changed in size).
I've used notifyDataSetChanged() in the adapter class. No result! I used an instance of adpater class in activity and called myAdapter.notifyDataSetChanged(). No result!
here is my code:
public class MainActivity extends Activity {
ListView lvfid;
FieldAdapter fAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some code
showFid();
}
private void showFiD(){
final ArrayList <HashMap<String,String>> al = new ArrayList<HashMap<String,String>>();
final Dialog dialog = new Dialog(MainActivity.this , R.style.DialogTheme);
dialog.setContentView(R.layout.field_dialog);
dialog.setCancelable(true);
dialog.show();
Button addField = (Button) dialog.findViewById(R.id.btnfidField);
lvfid = (ListView) dialog.findViewById(R.id.lvfid);
//Another plan i have tested, but no result:
//fAdapter = new FieldAdapter(dialog.getContext(),al);
//lvfid.setAdapter(fAdapter);
addField.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
HashMap<String,String> h = new HashMap<String,String>();
h.put("name", "");
h.put("value", "");
al.add(h);
lvfid.setAdapter(new FieldAdapter(dialog.getContext(), al));
//fAdapter.notifyDataSetChanged();
}
});
}
public class FieldAdapter extends BaseAdapter{
private ArrayList <HashMap <String,String>> arrayList;
private LayoutInflater inflater;
public FieldAdapter(Context context, ArrayList<HashMap <String,String>> arrayList) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.arrayList = arrayList;
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup arg2) {
View view = null;
if (convertView == null)
view = inflater.inflate(R.layout.field_inflater, null);
else
view = convertView;
Holder holder = new Holder();
holder.edName = (EditText) view.findViewById(R.id.edfidName);
holder.edValue = (EditText) view.findViewById(R.id.edfidValue);
//holder.edName.setText(arrayList.get(position).get("name"));
//holder.edValue.setText(arrayList.get(position).get("value"));
return view;
}
private class Holder {
private EditText edName;
private EditText edValue;
}
}
}
UPDATE:
I'm sorry i took everybody's time. The stupid problem was that my listview was inside a scrollview where it must not be! I hope this helps others who have the same issue!
Use the notifyDataSetChanged() every time the list is updated.
I had the same problem. I was facing with this problem when I wanted to update the listView after onDateChanged(). I resolved it with an extra ArrayList variable and an extra custom adapter in your case FieldAdapter variable.
Update your listView with a refresh adapter and array list variables after any operations. For example after button clicks.
1. Define a counter.
2. Check when the button is clicked, increase counter by one
3. Every time check the counter, if counter is greater than 1 it means the button is clicked more than once so update the list view with new variables (arrayList, FeildAdapter)
I recommend you to define the variables as a private class fields and name them such as refreshedArrayList and refreshedAdapter
Option
Try to use the ArrayAdapter. And don't create a new adapter every
time you click on the button.
only call the add(T o) function from the ArrayAdapter.
Other Option:
add a add function to your FieldAdapter in the add field adapter add the object to your arraylist and call notifiyDataSetChanged(the adapter has aslo one and the adapter notifies all his observers)
also don't create a new adapter every time you click the button.
public class MainActivity extends Activity {
ListView lvfid;
FieldAdapter fAdapter;
ArrayList <HashMap<String,String>> al ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some code
al = new ArrayList<HashMap<String,String>>();
lvfid.setAdapter(new FieldAdapter(MainActivity.this , al));
showFid();
}
private void showFiD(){
final Dialog dialog = new Dialog(MainActivity.this , R.style.DialogTheme);
dialog.setContentView(R.layout.field_dialog);
dialog.setCancelable(true);
dialog.show();
Button addField = (Button) dialog.findViewById(R.id.btnfidField);
lvfid = (ListView) dialog.findViewById(R.id.lvfid);
//Another plan i have tested, but no result:
//fAdapter = new FieldAdapter(dialog.getContext(),al);
//lvfid.setAdapter(fAdapter);
addField.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
HashMap<String,String> h = new HashMap<String,String>();
h.put("name", "");
h.put("value", "");
al.add(h);
fAdapter.notifyDataSetChanged();
}
});
}
I'm sorry i took everybody's time! The stupid problem was just my listview was inside a scrollview where it must not be! after getting the listview out of scrollview the problem got solved.

updating/refreshing List with custom ListAdapter

I am aware that there are plenty of similar questions, but they all have in common, that their solutions dont work with my list :(
I am trying to get my userList refreshing itself via the custom ArrayAdapter, when the database-contents are changed. In my case when i reset();
here my snippets (partial code):
MainActivity.java
public class MainActivity extends ListActivity {
private MyUserListAdapter myUserlistAdapter;
public ArrayList<User> myUserList = new ArrayList<User>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//shortened the list-filling. but it works properly!
User user = db.readUser(int);
myUserList.add(user);
myUserlistAdapter = new MyUserListAdapter(this, R.layout.row_main, myUserList);
setListAdapter(myUserlistAdapter);
//now when reset-button is hit, the listview should refresh itself
bReset.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//this is what is posted in most questions, but it does nothing for me
//myUserlistAdapter.notifyDataSetChanged();
//getListView().invalidateViews();
} });
and here myUserListAdapter.java:
public class MyUserListAdapter extends ArrayAdapter<User>{
private Context context;
private ArrayList<User> userList;
public MyUserListAdapter(Context context,
int textViewResourceId, ArrayList<User> userList) {
super(context, textViewResourceId, userList);
this.context = context;
this.userList = userList;
}
public View getView(int position, View v, ViewGroup parent) {
if (v == null) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(R.layout.row_main, null);
}
User user = getItem(position);
TextView tvUser = (TextView) v.findViewById(R.id.tvUser);
ImageView ivVoted = (ImageView) v.findViewById(R.id.ivVoted);
tvUser.setText(user.getName());
//abfrage ob hasVoted() = true muss noch eingebaut werden.
if (user.getVoted().equals("1"))
ivVoted.setImageResource(R.drawable.redcheck);
else
ivVoted.setImageResource(R.drawable.greencheck);
return v;
}
}
User.java is just a simple object-class. think its not the troublemaker here!
any help is appreciated!!! thx :-)
I am trying to get my userList refreshing itself via the custom
ArrayAdapter, when the database-contents are changed.
Since you are using ArrayAdapter and not CursorAdapter when you update data in database your adapter won't refresh itself. Whenever you want to update ListView you need to provide new datasource for Adapter.
One possible solution is to create setter in adapter subclass that will change datasource of adapter.
Pseudo code:
/* setter in adapter subclass */
public void changeDataSource(ArrayList<User> newUserList) {
this.userList = newUserList;
}
Then call adapter.notifyDataSetChanged(); for ListView update.
Try this:
arrayAdapter.clear()
for(Object o : objects)
arrayAdapter.add(o)
clear() and add() call to notifyDataSetChanged() itself.

How to add a Listview with SubItems

I would like to display the data in an array of string as the Subitems of the listview.
How exactly could I do it?
Is this what you are trying to achieve?
This is part of my code from an ap that uses fragments. One fragment is a list fragment.
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class Category List extends ListFragment {
final static String[] CATEGORIES = {"String1","String2",
"String3","String4"};
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1,
CATEGORIES));
Hope it helps.
Download the api demos from the Android Development site or open the SDK Manager and ensure you have downloaded Samples for your current SDK.
Then navigate to the samples folder and take a look at expandable lists. There are a few fully working examples there.
On my WinXP comp the files are located here:
C:\Program Files\Android\android-sdk\samples\android-16\ApiDemos\src\com\example\android\apis\view then look for the expandable lists.jar files
You need to create an Adapter class. Here is your solution:
First create a private class in your MainActivity class like this:
private class Adapter extends BaseAdapter
{
ArrayList<String> list;
public Adapter(ArrayList<String> list)
{
this.list=list;
}
#Override
public int getCount()
{
return list.size();
}
#Override
public String getItem(int index)
{
return list.get(index);
}
#Override
public long getItemId(int arg0)
{
return 0;
}
#Override
public View getView(int index, View view, ViewGroup arg2)
{
TextView tv_text = new TextView(MainActivity.this);
tv_text.setText(list.get(index));
tv_text.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
#SuppressWarnings("deprecation")
AbsListView.LayoutParams params =
new AbsListView.LayoutParams(AbsListView.LayoutParams.FILL_PARENT,
AbsListView.LayoutParams.FILL_PARENT);
tv_text.setLayoutParams(params);
tv_text.setHeight(60);
tv_text.setTextSize(18);
return tv_text;
}
}
then you need to put the Strings in ArrayList<String> :
ArrayList<String> list = new ArrayList<String>();
for(int i=0;i<yourArray.length(); i++) list.add(yourArray[i]);
after that you need to create an instance of the Adapter class:
Adapter adapter = new Adapter(list);
then you need to set the adapter as the main adapter of your ListView :
ListView lv_list = (ListView)findViewById(R.id.listView1);
lv.setAdapter(adapter);
D

How to let OnClick in ListView's Adapter call Activity's function

I have an Android application with a ListView in it, the ListView will setup fine but now I want a image in the ListView to be clickable. I do this by using 2 classes, the Activity class (parent) and an ArrayAdapter to fill the list. In the ArrayAdapter I implement a OnClickListener for the image in the list that I want to be clickable.
So far it all works.
But now I want to run a function from the activity class when the onClick, for the image in the list, is run but I do not know how. Below are the 2 classes that I use.
First the Activity class:
public class parent_class extends Activity implements OnClickListener, OnItemClickListener
{
child_class_list myList;
ListView myListView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// setup the Homelist data
myList = new child_class_list (this, Group_Names, Group_Dates);
myListView = (ListView) findViewById(R.id.list);
// set the HomeList
myListView.setAdapter( myList );
myListView.setOnItemClickListener(this);
}
void function_to_run()
{
// I want to run this function from the LiscView Onclick
}
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
// do something
}
}
And the ArrayAdapter from where I want to call a function from the Activity class:
public class child_class_list extends ArrayAdapter<String>
{
// private
private final Context context;
private String[] mName;
private String[] mDate;
public child_class_list (Context context, String[] Name, String[] Date)
{
super(context, R.layout.l_home, GroupName);
this.context = context;
this.mName = Name;
this.mDate = Date;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.l_home, parent, false);
ImageView selectable_image = (ImageView) rowView.findViewById(R.id.l_selectable_image);
selectable_image.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
// I want to run the function_to_run() function from the parant class here
}
}
);
// get the textID's
TextView tvName = (TextView) rowView.findViewById(R.id.l_name);
TextView tvDate = (TextView) rowView.findViewById(R.id.l_date);
// set the text
tvName.setText (mName[position]);
tvDate.setText (mDate[position]);
return rowView;
}
}
If anyone knows how to run the function in the activity class from the arrayadapter or how to set the image onClickListener in the Activity Class I would greatly apriciate the help.
Inside onClick() Do something like this:
((ParentClass) context).functionToRun();
Just for clarity to expand on provided answers
In a BaseAdapter you can get the parent class by calling this.getActivity();If you then typecast this to the actual activity class you can then call a function as per #AdilSoomro answer below so you actually end up with something like this
public class MyAdapter extends BaseAdapter<Long> {
public MyAdapter(Activity activity,
TreeStateManager<Long> treeStateManager, int numberOfLevels) {
super(activity, treeStateManager, numberOfLevels);
}
#Override
public void handleItemClick(final View view, final Object id) {
((MyActivity) this.activity).someFunction();
}
}
Then just declare someFunction in MyActivity to do what you want
protected void someFunction(){
// Do something here
}

Categories

Resources