When I debug the code, it is calling constructors in InviteListAdapter but it is not calling getView() method. I have tried multiple solutions available on stackoverflow but none of them works. Hope any one can find the mistake or solution for this.
invitableFriends.size()
returns value greater than 0.
InviteListAdapter
public class inviteListAdapter extends ArrayAdapter<JSONObject> {
private final Context context;
private final List<JSONObject> invitableFriends;
private ImageView profilePicView;
public inviteListAdapter(Context context, List<JSONObject> invitableFriends) {
super(context, R.layout.invite_adapter, invitableFriends);
this.context = context;
this.invitableFriends = invitableFriends;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(context.LAYOUT_INFLATER_SERVICE);
View listItemView = inflater.inflate(R.layout.invite_adapter, parent, false);
profilePicView = (ImageView) listItemView.findViewById(R.id.inviteListItemProfilePic);
TextView nameView = (TextView) listItemView.findViewById(R.id.inviteListItemName);
JSONObject currentUser = invitableFriends.get(position);
nameView.setText(currentUser.optString("first_name"));
return listItemView;
}
}
first.java
public View onCreateView (
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_first,container, false);
invitesGridView = (GridView)view.findViewById(R.id.invitesGridView);
return view;
}
final inviteListAdapter adapter = new inviteListAdapter(this,inviteFriendList);
invitesGridView.setAdapter(adapter);
adapter.notifyDataSetChanged();
public View onCreateView (
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_first,container, false);
invitesGridView = (GridView)view.findViewById(R.id.invitesGridView);
final inviteListAdapter adapter = new inviteListAdapter(this,inviteFriendList);
invitesGridView.setAdapter(adapter);
adapter.notifyDataSetChanged();
return view;
}
Call setAdapter inside onCreateView
Here you have to use context class static method. Like, change context to Context.LAYOUT_INFLATER_SERVICE
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Its not good practice to create inflater object in getView() method, Instead create one in constructor using LayoutInflater.from(context);
This link will help you out
How to use ArrayAdapter<myClass>
Related
I have ListView with Adapter, and also use holder. but later I read about recyclerView.ViewHolder and now confused, Is it different with the one I've been using right now? I mean for the optimization purpose, I want to know if using holder only is not good enough without using recyclerView.
public class NewsAdapter extends ArrayAdapter<News> {
Context context;
List<News> myList;
public NewsAdapter(Context context, int resource, List<News> objects) {
super(context, resource, objects);
this.context = context;
this.myList = objects;
}
#Override
public News getItem(int position) {
if(myList != null)
return myList.get(position);
return null;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
if (convertView == null){
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_news, null);
holder = new NewsAdapter.Holder();
holder.title = (TextView)convertView.findViewById(R.id.textViewTitle);
holder.datePosted = (TextView)convertView.findViewById(R.id.textViewDate);
holder.imageView = (ImageView)convertView.findViewById(R.id.imageViewThumbnailpic);
convertView.setTag(holder);
}else{
holder = (Holder)convertView.getTag();
}
News news = getItem(position);
holder.title.setText(news.getTitle());
holder.datePosted.setText(news.getDatePost());
Picasso.with(context)
.load(news.getImgUrl())
.placeholder(R.drawable.coin25)
.error(R.drawable.hnbspic)
.into(holder.imageView);
return convertView;
}
private class Holder{
ImageView imageView;
TextView title;
TextView datePosted;
}
}
It's better to use Recyclerview because it has been optimized for various scenarios and not just for View holder pattern like it give the option for determining how your item should be laid out or like what should be the animation or custom drawing in each item.You can read more this medium post
I need to call a function in my portfolioActivity Fragment which comes from the class portfolioListAdapter.
It says my parameters are incorrect.
This function works just fine when I'm not using a Fragment, but as I am linking my Fragment to a navigation drawer, it is necessary to keep it this way.
Here is my Fragment:
public class portfolioActivity extends Fragment {
ListView portfolioList;
String[] stockTicker={"AAPL", "GOOG", "MSFT"};
double[] stockPrice={138.96, 830.63, 64.01};
int[] shares={5, 2, 10};
double[] percentChange={0.59, 0.55, 1.43};
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.portfolio_layout, container, false);
portfolioList = (ListView) getView().findViewById(R.id.portfolioListView);
//ADAPTER
ListAdapter adapter = new portfolioListAdapter(this, stockTicker, stockPrice, shares, percentChange);
portfolioList.setAdapter(adapter);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("Portfolio");
}
}
The error comes when I try to call portfolioListAdapter().
It says there is a problem with the "this" parameter.
Here is my other class:
public class portfolioListAdapter extends ArrayAdapter<String> {
//DECLARATIONS
String[] stockTicker={};
double[] stockPrice={};
int[] shares={};
double[] percentChange={};
Context c;
LayoutInflater inflater;
public portfolioListAdapter(Context context, String[] stockTicker,
double[] stockPrice, int[] shares, double[] percentChange) {
super(context, R.layout.portfolio_row_model, stockTicker);
this.c=context;
this.stockTicker=stockTicker;
this.stockPrice=stockPrice;
this.shares=shares;
this.percentChange=percentChange;
}
public class ViewHolder
{
TextView stockTicker;
TextView stockPrice;
TextView shares;
TextView totalValue;
TextView percentChange;
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null)
{
inflater=(LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView=inflater.inflate(R.layout.portfolio_row_model, null);
}
// OUR VIEWHOLDER OBJECT
final ViewHolder holder = new ViewHolder();
//INITIALIZE VIEWS
holder.stockTicker= (TextView) convertView.findViewById(R.id.list_portfolio_ticker);
holder.stockPrice= (TextView) convertView.findViewById(R.id.list_portfolio_price);
holder.shares= (TextView) convertView.findViewById(R.id.list_portfolio_shares);
holder.totalValue= (TextView) convertView.findViewById(R.id.list_portfolio_value);
holder.percentChange= (TextView) convertView.findViewById(R.id.list_portfolio_change);
//ASSIGN VIEWS
holder.stockTicker.setText(stockTicker[position]);
holder.stockPrice.setText(String.valueOf("$"+stockPrice[position]));
holder.shares.setText(String.valueOf(shares[position]));
holder.totalValue.setText(String.valueOf("$"+(stockPrice[position]*shares[position])));
holder.percentChange.setText(String.valueOf(percentChange[position]+"%"));
//return super.getView(position, convertView, parent);
return convertView;
}
}
You can't put code after return.
And your parameters are wrong. this is a Fragment, not a Context, you need to use getActivity() or (preferably) onAttach there.
private ListView portfolioList;
private PortfolioListAdapter adapter;
#Override
public void onAttach(Context context) {
super.onAttach(activity);
( (Activity) context).setTitle("Portfolio");
adapter = new PortfolioListAdapter(context, stockTicker, stockPrice, shares, percentChange);
portfolioList.setAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.portfolio_layout, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
portfolioList = (ListView) view.findViewById(R.id.portfolioListView);
}
Note: You also are not using the ViewHolder correctly.
Might want to read back over how to do that (or use a RecyclerView)
1) Can't put code after return.
2) Constructor for adapter is expecting a "Context" object. What you are passing is a fragment object(this)
Add this code fragment
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
And in call to adapter pass mContext instead of this.
why in every example i see that extends the class ArrayAdapter it overrides the constructor that accepts T[] objects and references its own private variable to that and uses the referenced variable in the override of getView?
how can this be dynamic adding of objects?
will values be updated when a new item is added to the ArrayAdapter using add method?
can i instead of implementing my own adapter just use addheaderview in listview?
public class MySimpleArrayAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] values;
public MySimpleArrayAdapter(Context context, String[] values) {
super(context, R.layout.rowlayout, values);
this.context = context;
this.values = values;
}
#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.rowlayout, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label);
ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
textView.setText(values[position]);
// change the icon for Windows and iPhone
String s = values[position];
if (s.startsWith("iPhone")) {
imageView.setImageResource(R.drawable.no);
} else {
imageView.setImageResource(R.drawable.ok);
}
return rowView;
}
}
I have this Adapter that displays custom listview to my layout:
public class AttendedBaseAdapter extends ArrayAdapter<DashboardListing> {
private List<DashboardListing> items;
private Activity activity;
private static View v, vDashboard;
public AttendedBaseAdapter(Activity a, int textViewResourceId, List<DashboardListing> items){
super(a, textViewResourceId, items);
activity = a;
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
v = convertView;
vDashboard = convertView;
final DashboardListing attended = items.get(position);
LayoutInflater vi = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row_attended, parent, false);
LayoutInflater viDashboard = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vDashboard = viDashboard.inflate(R.layout.fragment_dashboard, parent, false);
SmartImageView imgVenue = (SmartImageView) v.findViewById(R.id.event_poster_url);
imgVenue.setImageUrl(attended.getPoster());
TextView txtEventName = (TextView) v.findViewById(R.id.event_name);
TextView txtVenueName = (TextView) v.findViewById(R.id.event_venue_name);
txtEventName.setText(attended.getName());
txtVenueName.setText(attended.getVenue());
TextView txtAttendedCount = (TextView) vDashboard.findViewById(R.id.txt_attended_count);
txtAttendedCount.setText("100");
return v;
}
}
In this part of method getView(...):
#Override
public View getView(int position, View convertView, ViewGroup parent) {
v = convertView;
vDashboard = convertView;
final DashboardListing attended = items.get(position);
LayoutInflater vi = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row_attended, parent, false);
LayoutInflater viDashboard = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vDashboard = viDashboard.inflate(R.layout.fragment_dashboard, parent, false);
SmartImageView imgVenue = (SmartImageView) v.findViewById(R.id.event_poster_url);
imgVenue.setImageUrl(attended.getPoster());
TextView txtEventName = (TextView) v.findViewById(R.id.event_name);
TextView txtVenueName = (TextView) v.findViewById(R.id.event_venue_name);
txtEventName.setText(attended.getName());
txtVenueName.setText(attended.getVenue());
TextView txtAttendedCount = (TextView) vDashboard.findViewById(R.id.txt_attended_count);
txtAttendedCount.setText("100");
return v;
}
How can I return multple(not just the View v but I also want to return the View vDashboard? because I have 2 layouts View v refers to R.layout.row_attended and View vDashboard refers to R.layout.fragment_dashboard
How can I return multple(not just the View v but I also want to return the View vDashboard?
You would need to wrap them in some sort of container (e.g., LinearLayout) with rules for how they should be sized and positioned within that container, then return the container from getView().
Even easier would be to combine the layout files, directly or using <include> elements, so that you only are inflating one layout.
In other words, getView() returns the one View that is to be the ListView row (or GridView cell or whatever) for the given position. That View can be a ViewGroup populated by whatever you want, so long as it meets your UI requirements.
I have made my own CustomArrayAdapter to show list of Brazilian Restaurants. I have overidden the GetView method to make my own custom view.
private class MyAdapter extends ArrayAdapter<String> {
public MyAdapter(Context context, int resource, int textViewResourceId,
String[] strings) {
super(context, resource, textViewResourceId, strings);
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item, parent,false);
String [] items= getResources().getStringArray(R.array.locations_array);
TextView tv= (TextView) row.findViewById(R.id.textView1);
ImageView iv = (ImageView) row.findViewById(R.id.imageView1);
tv.setText(items[position]);
iv.setImageResource(R.drawable.brazil);
return row;
}
}
Currently this new GetView class is pulling in a text string from a resource xml file and putting it into the list item.
If I wanted to incorporate an array of extra data generated within the app, I assume that I don't do the array generating in the GetView class as this will be recreated each time a new row is made.
Where do I put the code to make the array, and how do I call this data into the GetView code above?
It's worth pointing out that for better performance you should be making use of the convertView variable passed into the getView() method.
The use of convertView allows you to re-use list item views instead of creating new ones which has a heavy performance hit. If you have a large data set or value performance in your app, you would do well to check out the documentation for getView()
Your code would then look something more like this:
...
//it's also worth moving these methods to your constructor so they aren't called every time getView() for better performance
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
String [] items= getResources().getStringArray(R.array.locations_array);
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
convertView = inflater.inflate(R.layout.list_item, parent, false);
TextView tv= (TextView) convertView.findViewById(R.id.textView1);
ImageView iv = (ImageView) convertView.findViewById(R.id.imageView1);
tv.setText(items[position]);
iv.setImageResource(R.drawable.brazil);
return row;
}
...
Building on #CodeDownZero's answer, I highly recommend you adopt the ViewHolder pattern, and definitely recycle your listviews (using convertview).
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(textViewResourceId, parent, false);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.tv1 = (TextView) view.findViewById(R.id.textView1);
viewHolder.tv2 = (TextView) view.findViewById(R.id.textView2);
view.setTag(viewHolder);
} else {
view = convertView;
}
ViewHolder holder = (ViewHolder) view.getTag();
MyDataClass data = this.getItem(position);
holder.tv1.setText(data.street);
holder.tv2.setText(data.name);
return view;
}
...
private class ViewHolder {
private TextView tv1;
private TextView tv2;
}
You can base an ArrayAdapter on a custom class instead of string. Here is an example:
public class MyDataClass {
public String street;
public String name;
}
private class MyAdapter extends ArrayAdapter<MyDataClass> {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item, parent,false);
TextView tv1= (TextView) row.findViewById(R.id.textView1);
TextView tv2= (TextView) row.findViewById(R.id.textView2);
MyDataClass data = this.getItem(position);
tv1.setText(data.street);
tv2.setText(data.name);
return row;
}
}
To populate the Adapter with data you can use this snippet in the OnCreate method of the Activity:
..
MyAdapter adapter = new MyAdapter();
MyDataClass lData = new MyDataClass(); // here was a mistake
lData.name = "MyName";
lData.street = "MyRoad";
adapter.Add(lData);
..
ListView.Adapter=adapter; // where Listview is the Listview