heap size while scrolling in listView - android

In list-view while scrolling through List-view heap-size is continuously increasing, it reaches to 64MB on Galaxy S3 device and application gets crashed.
public class GAdapter extends BaseAdapter implements Filterable {
private List<G> list;
private GActivity mContext;
private Drawable attach , text;
private HttpImageManager mHttpImageManager;
private LayoutInflater mInfalotar;
public GAdapter(GActivity context , List<G> list){
this.list = list;
mContext = context;
mInfalotar = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mHttpImageManager = ((GApplication)context.getApplication()).getHttpImageManager();
attach = mContext.getResources().getDrawable(R.drawable.ic_attachment);
text = mContext.getResources().getDrawable(R.drawable.ic_text);
}
public void addContact(VamooseGroup entry){
list.add(entry);
notifyDataSetChanged();
}
public void setGroupList(List<G> g){
list.clear();
datavalues = null;
list.addAll(g);
notifyDataSetChanged();
}
#Override
public int getCount(){
return (list.size()+1);
}
#Override
public Object getItem(int index) {
if(index != list.size())
return list.get(index);
else
return null;
}
#Override
public long getItemId(int index) {
return index;
}
#Override
public int getViewTypeCount() {
return list.size()+1;
}
#Override
public int getItemViewType(int position) {
return position == list.size() ? 1 : 0;
}
#Override
public View getView(int index, View convertview, ViewGroup viewGroup) {
int type = getItemViewType(index);
switch(type){
case 0 :
convertview = mInfalotar.inflate(R.layout.data_listitem , viewGroup, false);
ImageView myimageView = (ImageView)convertview.findViewById(R.id.myImage);
TextView groupname = (TextView)convertview.findViewById(R.id.groupname);
TextView timespam = (TextView)convertview.findViewById(R.id.timeInfo);
TextView msgSender = (TextView)convertview.findViewById(R.id.msgowner);
TextView draft = (TextView)convertview.findViewById(R.id.draft);
ImageView watchIcon = (ImageView)convertview.findViewById(R.id.time);
ImageView attachment = (ImageView)convertview.findViewById(R.id.attachment);
final G g = list.get(index);
String grouppic = g.pic();
if(ImageValidator.validate(grouppic)){
Bitmap bitmap = mHttpImageManager.loadImage(new HttpImageManager.LoadRequest(Uri.parse(grouppic), myimageView));
if (bitmap != null && !bitmap.isRecycled()) {
myimageView.setImageBitmap(bitmap);
}
}
parent.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.select));
groupname.setText("FOO1");
msgbox.setText("FOO2");
groupname.setText("F003");
msgSender.setText("F004");
timespam.setText("F005");
attachment.setBackgroundDrawable(attach);
watchIcon.setBackgroundDrawable(text);
break;
}
return convertview;
}
}
above code is List-adapter used. i'm using the the following library for showing the images
android-http-image-manager
can someone tell me why bitmaps are not getting recycled? heap is continuously increasing while scrolling list-view and reaches to 64MB.please provide a brief solution.

A ListView is smart and there are many ways to recycle your views to increase the performance. One of these is to implement the ViewHolder-pattern.
But this will not solve your problem. The problem you are facing is that you have overriden the getViewTypeCount() method and returning a huge number. The ListView won't recycle any view because for each row, you have a different type.
You can solve your problem by not overriding this method, or returning the number of different row types. This means.. If you have 2 different layouts available for your list. You return 2.
#Override
public int getViewTypeCount() {
return 2;
}

Related

I meet a something wrong about IndexOutOfBoundsException

I have a Json data like ,I want to show the information in my listView so I parse them into a ArrayList<String> and then add to the adapter.
{
"areas": [
{
"fieldTag": "1",
"areaId": 2,
"areaName": "No.1",
"devices": [
{
"cameraName": "A",
"busyFields": "null",
"freeFields": "No.1,NO,2",
},{
"cameraName": "B"
"busyFields": "null",
"freeFields": "No.3,No.4",
}
]
}
],
"error": 0,
"message": "ok"
}
and I use Gson to parse it and I make the data to a list for show them in the Adapter,my code is :
if (mDeviceInfo.getError() == 0) {
for (int i = 0; i<mDeviceInfo.getAreas().size();i++){
adapter.addSectionHeaderItem(mDeviceInfo.getAreas().get(i).getAreaName());
for (int k = 0; k<mDeviceInfo.getAreas().get(i).getDevices().size();k++){
adapter.addItem(mDeviceInfo.getAreas().get(i).getDevices().get(k).getCameraName());
mPositionList.add(mDeviceInfo.getAreas().get(i).getDevices().get(k).getPosition());
mFreeFieldsList.add(mDeviceInfo.getAreas().get(i).getDevices().get(k).getFreeFields());
mBusyFieldsList.add(mDeviceInfo.getAreas().get(i).getDevices().get(k).getBusyFields());
}
}
adapter.addMessage(mPosition,mFreeFields,mBusyFields);
}else {
Toast.makeText(this,"get info failed",Toast.LENGTH_SHORT).show();
}
and that is my code as the Adapter:
public class CameraListAdapter extends BaseAdapter {
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private ArrayList<String> mData = new ArrayList<String>();
private ArrayList<String> mPosition = new ArrayList<>();
private ArrayList<String> mFreeFields = new ArrayList<>();
private ArrayList<String> mBusyFields = new ArrayList<>();
private TreeSet<Integer> sectionHeader = new TreeSet<Integer>();
private LayoutInflater mInflater;
public CameraListAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void addItem(final String item) {
mData.add(item);
notifyDataSetChanged();
}
public void addSectionHeaderItem(final String item) {
mData.add(item);
sectionHeader.add(mData.size() - 1);
notifyDataSetChanged();
}
public void addMessage(ArrayList<String> position,ArrayList<String> freeFields,ArrayList<String> busyFields){
mPosition = position;
mFreeFields = freeFields;
mBusyFields = busyFields;
}
#Override
public int getItemViewType(int position) {
return sectionHeader.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public String getItem(int position) {
return mData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public boolean isEnabled(int position) {
return getItemViewType(position) != TYPE_SEPARATOR;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
int rowType = getItemViewType(position);
if (convertView == null) {
viewHolder = new ViewHolder();
switch (rowType) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.cameradetail, null);
viewHolder.mCameraName = (TextView) convertView.findViewById(R.id.cameraName);
Log.d("CameraListAdapter","position "+position);
viewHolder.mCameraName.setText(mData.get(position));
viewHolder.position = (TextView) convertView.findViewById(R.id.cameraposition);
viewHolder.position.setText(mPosition.get(position));
viewHolder.busyFields = (TextView) convertView.findViewById(R.id.busyfields);
viewHolder.busyFields.setText(mBusyFields.get(position));
viewHolder.freeFields = (TextView) convertView.findViewById(R.id.freefields);
viewHolder.freeFields.setText(mFreeFields.get(position));
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.cameratag, null);
viewHolder.mTag = (TextView) convertView.findViewById(R.id.areaName);
viewHolder.mTag.setText(mData.get(position));
break;
}
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
return convertView;
}
public static class ViewHolder {
public TextView mTag;
public TextView mCameraName;
public TextView position;
public TextView busyFields;
public TextView freeFields;
}
}
But it always show me that
java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at .CameraListAdapter.getView(CameraListAdapter.java:106)
It upset me for 2 days so are there anyone to help me ?Thank you so much
In an Adapter, the size of the data is determined by getCount, which you defined like so.
#Override
public int getCount() {
return mData.size();
}
This means that the range of positions in getView is 0 to the value returned by getCount.
But, you seem to have 4 lists of various sizes, or at least not the same size as mData
private ArrayList<String> mData = new ArrayList<String>();
private ArrayList<String> mPosition = new ArrayList<>();
private ArrayList<String> mFreeFields = new ArrayList<>();
private ArrayList<String> mBusyFields = new ArrayList<>();
I'm not sure which one is causing the problem, but, for example, this will throw an exception if mPosition doesn't hold the same amount of data as mData
viewHolder.position.setText(mPosition.get(position));
I would recommend you not have 4 separate String Arraylists since that data seems to pertain to a single Object, which if you want a proper custom Adapter, you give it a list of your Object type (parsed from Gson, for example) instead of individual pieces of an Object
When you use
#Override
public int getCount() {
return mData.size();
}
you basically tell the adapter to call the getView() method for every item in you mData list. The position argument in your getView() method corresponds to the entry in your mData list. You then use that same position argument to get data out of three other lists that are probably of different size than the mData list so one of the get(position) calls on one of the other lists will throw the exception you are seeing. This can be easily debugged if you use the debugger in Android Studio on line 106 in your adapter.

CursorAdapter with two row layouts

Okey so, since I've not found a consistent way of doing this when I searched, I decided that maybe putting my code for somebody elses eyes to see might help.
I'm creating a game where you use cards. These cards can either be locked or unlocked depending on different factors. The important thing is, that I want to check the sqlite db whether they are locked, then display different row layouts for the two possible outcomes.
Here's my code:
public class AllCardsAdapter extends CursorAdapter {
LockedHolder viewLocked;
UnlockedHolder viewUnlocked;
private LayoutInflater mInflater;
public static final int LOCKED = 0;
public static final int UNLOCKED = 1;
public AllCardsAdapter(Context context, Cursor cursor) {
super(context, cursor);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
final int type;
int viewType = this.getItemViewType(cursor.getInt(cursor.getColumnIndex("unlocked")));
if (viewType == 1){
type = UNLOCKED;
} else {
type = LOCKED;
}
if (type == LOCKED){
viewLocked = (LockedHolder) view.getTag();
viewLocked.nameHolder.setText(cursor.getString(cursor.getColumnIndex("name")));
viewLocked.awardedAtHolder.setText("Awarded at level:");
viewLocked.reqLvlHolder.setText(cursor.getString(cursor.getColumnIndex("reqlvl")));
String imagePath = cursor.getString(cursor.getColumnIndex("image"));
if (imagePath.equals("card_obj_plus_1")){
Picasso.with(context).load(R.drawable.card_obj_plus_1).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_2")){
Picasso.with(context).load(R.drawable.card_obj_plus_2).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_3")){
Picasso.with(context).load(R.drawable.card_obj_plus_3).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_slowdown")){
Picasso.with(context).load(R.drawable.card_slowdown).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_speed_up")){
Picasso.with(context).load(R.drawable.card_speed_up).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
} else {
viewUnlocked = (UnlockedHolder) view.getTag();
viewUnlocked.nameHolder.setText(cursor.getString(cursor.getColumnIndex("name")));
String imagePath = cursor.getString(cursor.getColumnIndex("image"));
if (imagePath.equals("card_obj_plus_1")){
Picasso.with(context).load(R.drawable.card_obj_plus_1).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_2")){
Picasso.with(context).load(R.drawable.card_obj_plus_2).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_3")){
Picasso.with(context).load(R.drawable.card_obj_plus_3).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_slowdown")){
Picasso.with(context).load(R.drawable.card_slowdown).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_speed_up")){
Picasso.with(context).load(R.drawable.card_speed_up).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
viewLocked = new LockedHolder();
viewUnlocked = new UnlockedHolder();
final int type;
int viewType = this.getItemViewType(cursor.getInt(cursor.getColumnIndex("unlocked")));
if (viewType == 1){
type = UNLOCKED;
} else {
type = LOCKED;
}
System.out.println(viewType);
System.out.println(type);
if (type == LOCKED){
View lockedView;
lockedView = mInflater.inflate(R.layout.card_list_row_disabled, parent, false);
viewLocked.nameHolder = (TextView) lockedView.findViewById(R.id.txtTitle);
viewLocked.imageHolder = (ImageView) lockedView.findViewById(R.id.imgThumbnail);
viewLocked.reqLvlHolder = (TextView) lockedView.findViewById(R.id.tvLevelNr);
viewLocked.awardedAtHolder = (TextView) lockedView.findViewById(R.id.tvAwardedAt);
lockedView.setTag(viewLocked);
return lockedView;
} else {
View unlockedView;
unlockedView = mInflater.inflate(R.layout.card_list_row, parent, false);
viewUnlocked.nameHolder = (TextView) unlockedView.findViewById(R.id.txtTitle);
viewUnlocked.imageHolder = (ImageView) unlockedView.findViewById(R.id.imgThumbnail);
unlockedView.setTag(viewUnlocked);
return unlockedView;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
return position % 2;
}
public class LockedHolder {
public TextView nameHolder;
public ImageView imageHolder;
public TextView awardedAtHolder;
public TextView reqLvlHolder;
}
public class UnlockedHolder {
public TextView nameHolder;
public ImageView imageHolder;
}
}
The error I'm getting is on the row "viewLocked = (LockedHolder) view.getTag();"
AllCardsAdapter$UnlockedHolder cannot be cast to AllCardsAdapter$LockedHolder
The error only shows up when I have a list containing cards that are both locked and unlocked.
See I know what it's trying to do, I just don't know why. Also, if I'm overcomplicating things for no good reason, or missing something obvious, I'd be much appreciated if you find it..
getItemViewType implementation does not look right (type does not depend on item position) it should be something like the following
private int getItemViewType(Cursor cursor) {
return cursor.getInt(cursor.getColumnIndex("unlocked")) % 2;
}
#Override
public int getItemViewType(int position) {
Cursor cursor = (Cursor) getItem(position);
return getItemViewType(cursor);
}
You also need to update bindView and newView
int viewType = this.getItemViewType(cursor);

android ListView adapter method getViewTypeCount() not fire when adapter.notifyDataSetChanged()

I want my listview load every 10 item and not want my listview reuse item.
1.I load 10 item and set adapter to listview and in adapter class i call method getViewTypeCount() like this.
(current in itemList is has 10)
public int getViewTypeCount() {
return itemList.size();
}
2.I debug in getViewTypeCount() it return value 10.
3.Then i add new 10 item to itemList(current in itemList is has 20) and call adapter.notifyDataSetChanged()
4.When i scroll my listview down it work but when i scroll up it's error(unfortunately)
5.I found the problem because getViewTypeCount() not fire after adapter.notifyDataSetChanged() it's not return 20 (i know because i test return 500 in getViewTypeCount() it's work and not error.)
6.I want my list view load every 10 item and i don't want my listview reuse position. How to solve it's?.
Edit
this is my adapter class
public class ContentListAdapter extends BaseAdapter {
private Context context;
private ArrayList<ContentInfo> Content;
private LayoutInflater Layf;
public ContentListAdapter(Context context, ArrayList<ContentInfo> content){
this.context = context;
this.Content = content;
this.Layf = LayoutInflater.from(context);
}
#Override
public int getCount() {
return Content.size();
}
#Override
public Object getItem(int position) {
return Content.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public int getViewTypeCount() {
return Content.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = Layf.inflate(R.layout.content_list_item, null);
}
ImageView img_ContentImage = (ImageView) convertView.findViewById(R.id.img_ContentImage);
TextView tv_ContentName = (TextView) convertView.findViewById(R.id.tv_ContentName);
TextView tv_ContentDate = (TextView) convertView.findViewById(R.id.tv_ContentDate);
TextView tv_ContentViews = (TextView) convertView.findViewById(R.id.tv_ContentViews);
if(img_ContentImage != null){
if(Content.get(position).getPicture().length() > 0)
new DownloadImageViewTask(img_ContentImage).execute(Content.get(position).getPicture());
}
if(tv_ContentName != null)
tv_ContentName.setText(Content.get(position).getTitle().replace(" "," ").replace("-", "–"));
if(tv_ContentDate != null) {
if(Content.get(position).getPublishDate().length() > 0) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date dt = sdf.parse(Content.get(position).getPublishDate());
String year = new SimpleDateFormat("yyyy", new Locale("th", "TH")).format(dt);
String byear = (Integer.parseInt(year) + 543) + "";
tv_ContentDate.setText((new SimpleDateFormat("d MMM yyyy", new Locale("th", "TH")).format(dt)).replace(year, byear));
}catch (Exception e){
}
}
}
if(tv_ContentViews != null){
DecimalFormat formatter = new DecimalFormat("#,##0");
tv_ContentViews.setText(formatter.format(Content.get(position).getViews()));
}
return convertView;
}
}
getViewTypeCount() only called when you call setAdapter.

Listviews with EditText behavior

i've noticed an extrage behavior on my app that has a ListView with three EditTexts,
the problem is that whenever i select one textedit and move away from focus and come back the text i wrote in the first row i selected either desapears or moves to a different row, also when an edittext is focused and i go down in the list it seems that i have selected the edittext in the same position but 10 or 11 rows after the one im actually focusing(the one i can write to).
any knowledge on that case?
also im new to android so i dont know if thats supposed to happen.
this is the List im using.
public class In_List {
private int id;
private String text;
private float a;
private float Qty;
public In_List (int id, String text, float a, float Qty) {
this.id = id;
this.text = text;
this.a = a;
this.Qty= Qty;
}
public String get_text() {
return text;
}
public float get_a() {
return a;
}
public int get_id() {
return id;
}
public float get_Qty() {
return Qty;
}
}
here is the adapter:
public abstract class List_Adapter extends BaseAdapter {
private ArrayList<?> ins;
private int R_layout_IdView;
private Context context;
public Lista_adaptador(Context context, int R_layout_IdView, ArrayList<?> ins) {
super();
this.context = context;
this.ins = ins;
this.R_layout_IdView = R_layout_IdView;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R_layout_IdView, null);
}
onInsert (ins.get(position), view);
return view;
}
#Override
public int getCount() {
return ins.size();
}
#Override
public Object getItem(int position) {
return ins.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public abstract void onInsert (Object insert, View view);
}
and here is the main activity. it has a popup window that i used to fill the value of Qty but i its not included.
public class MainActivity extends Activity {
private ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listing);
ArrayList<In_List> data = new ArrayList<>();
for(int i=0; i<100; i++){
data.add(new In_List(i, "Item Number :"+i+1, i*2,0));
}
list = (ListView) findViewById(R.id.ListView_listing);
list.setAdapter(new List_Adapter(this, R.layout.entry, data){
#Override
public void onInsert(Object entr, View view) {
if (entr != null) {
TextView id_Text = (TextView) view.findViewById(R.id.textView_id);
if (id_Text != null)
id_Text.setText(((In_List) entr).get_id());
TextView info_Text = (TextView) view.findViewById(R.id.textView_info);
if (info_Text != null)
info_Text.setText(((In_List) entr).get_text());
TextView inside_Text = (TextView) view.findViewById(R.id.textView_inside);
if (inside_Text != null)
inside_Text.setText(((In_List) entr).get_a());
TextView Qty_Text = (TextView) view.findViewById(R.id.textView_qty);
if (Qty_Text != null || Qty_Text.getText().toString().equals(0))
Qty_Text.setText(((In_List) entr).get_Qty());
Qty_Text.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Add_Qty();
}
});
}
}
});
// list.setOnItemClickListener(new OnItemClickListener() {
// #Override
// public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// In_List chosen = (In_List) parent.getItemAtPosition(position);
//
// CharSequence text = "Selected: " + chosen.get_textoDebajo();
// Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
// toast.show();
// }
// });
}
}
now, when i scroll down through the list the Qtys that i have entered either disappear or move to another row.
fixed. i wasn't stablishing Qty_Text value at all. also made a method to save into the adapter array.
EditTexts in generally are very tricky. And using them inside a ListView is almost impossible. The special behaviour of EditTexts for example to always automatically assume focus combinded with the View recycling of the ListViews messes with the ListView and causes a lot of problems. I would suggest you look for another solution. For example placing the EditText inside the HeaderView of the ListView is fine, as the HeaderView is not recycled as you scroll through the ListView.

Section Headers in Navigation Drawer Listview

I want to implement section headers similar to the one used by pirate Bay
Basically a Listview like this:
header Name
list Item
list Item
list Item
list Item
header Name
list Item
list Item
list Item
Which is the best way to achieve this? I have read on section headers and merge adapters but they are not working to my needs...How would I achieve section headers
Here is how I solved it:
I taught my custom ListAdapter to return heading rows as well as detail rows ,this involves overriding methods getViewTypeCount() and getItemViewType() in your ListAdapter, plus I got getView() to know the difference between the row types. The following code should give you a hint..The code for ListViewAdapter (commented most parts)
public class ListViewAdapter extends ArrayAdapter<ListViewItemModel> {
public ListViewAdapter(Context context) {
super(context, 0);
}
public void addHeader(int title) { //expects The Title for the header as an Arugment to it
add(new ListViewItemModel(title, -1, true));//add the object to the Bottom of the array
}
public void addItem(int title, int icon) {
add(new ListViewItemModel(title, icon, false));
}
public void addItem(ListViewItemModel itemModel) {
add(itemModel);
}
#Override
public int getViewTypeCount() { //Returns the number of types of Views that will be created by getView(int, View, ViewGroup).
return 2; //we will create 2 types of views
}
#Override
public int getItemViewType(int position) { //framework calls getItemViewType for row n, the row it is about to display.
//Get the type of View that will be created by getView(int, View, ViewGroup) for the specified item.
return getItem(position).isHeader ? 0 : 1; // get position passes (n) and accertain is its a header or not
}
#Override
public boolean isEnabled(int position) {
return !getItem(position).isHeader;
}
public static class ViewHolder {
public final TextView textHolder;
public final ImageView imageHolder;
public ViewHolder(TextView text1, ImageView image1) {
this.textHolder = text1;
this.imageHolder = image1;
}
}
public View getView(int position, View convertView, ViewGroup parent) {
//Abstract View --> Get a View that displays the data at the specified position in the data set.
ListViewItemModel item = getItem(position);
ViewHolder holder = null;
View view = convertView;
if (view == null) {
int layout = R.layout.list_view_row;
if (item.isHeader)
layout = R.layout.list_view_row_header;
view = LayoutInflater.from(getContext()).inflate(layout, null);
TextView text1 = (TextView) view.findViewById(R.id.menurow_title);
ImageView image1 = (ImageView) view.findViewById(R.id.menurow_icon);
view.setTag(new ViewHolder(text1, image1));
}
if (holder == null && view != null) {
Object tag = view.getTag();
if (tag instanceof ViewHolder) {
holder = (ViewHolder) tag;
}
}
if (item != null && holder != null) {
if (holder.textHolder != null)
holder.textHolder.setText(item.title);
if (holder.imageHolder != null) {
if (item.iconRes > 0) {
holder.imageHolder.setVisibility(View.VISIBLE);
holder.imageHolder.setImageResource(item.iconRes);
} else {
holder.imageHolder.setVisibility(View.GONE);
}
}
}
return view;
}
}
And a Model for the ArrayAdapter to use
public class ListViewItemModel {
public int title;
public int iconRes;
public boolean isHeader;
public ListViewItemModel(int title, int iconRes, boolean header) {
this.title = title;
this.iconRes = iconRes;
this.isHeader = header;
}
public ListViewItemModel(int title, int iconRes) {
this(title, iconRes, false);
}
}
Now in the class that I will be using this custom listview in the navigation
ListViewAdapter mAdapter = new ListViewAdapter(this);// Add First Header
mAdapter.addHeader(R.string.menu_data);
menu_One = getResources().getStringArray(R.array.menu_one); // Load list view data array strings
String[] menuOneIcons = getResources().getStringArray(R.array.menu_two_one);// Load list view image array strings
int oneIcons = 0;
for (String item : menuItemsData) { //enhanced For loop, iterate on elements from the collection named menuItemsData
int id_menu_one = getResources().getIdentifier(item, "string",this.getPackageName());
int id_menu_one_icons = getResources().getIdentifier(menuOneIcons[oneIcons], "drawable",this.getPackageName());
ListViewItemModel mItem = new ListViewItemModel(id_data_title,id_data_icon);
mAdapter.addItem(mItem);
oneIcons++;
}
// Add second header
mAdapter.addHeader(R.string.menu_two); //second Header here
menu_Two = getResources().getStringArray(R.array.menu_two);
String[] menuTwoIcons = getResources().getStringArray(R.array._menu_two_icons);
int twoIcons = 0;
for (String item : menu_Two) {
int id_menu_two = getResources().getIdentifier(item, "string",this.getPackageName());
int id_menu_two_icons = getResources().getIdentifier(enuTwoIcons[twoIcons], "drawable",this.getPackageName());
// creating drawer menu model
ListViewItemModel mItem = new ListViewItemModel(id_menu_two,id_menu_two_icons);
mAdapter.addItem(mItem);
twoIcons++;
}
Just use an ExpandableListView with one group per header.

Categories

Resources