0

I have seen the model created in this question: A generic MVC ArrayAdapter class

This is the adapter class:

public class MVCArrayAdapter<ModelType> extends BaseAdapter{
Activity ctx;
ArrayList<ModelType> array = new ArrayList<ModelType>();
Constructor<?> viewConstructor;

public MVCArrayAdapter(Activity context, String viewClassName) throws NoSuchMethodException, ClassNotFoundException {
    super();
    ctx = context;
    viewConstructor = Class.forName(viewClassName).getConstructor(Activity.class);
}


public int getCount() {
    return array.size();
}

public Object getItem(int position) {
    return array.get(position);
}

public long getItemId(int position) {
    return position;
}

@SuppressWarnings("unchecked")
public View getView(int position, View convertView, ViewGroup parent) {
    ListViewRow<ModelType> view = (ListViewRow<ModelType>)convertView;
    if (view == null) {
        try {
            view = (ListViewRow<ModelType>)viewConstructor.newInstance(ctx);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    view.setModel((ModelType)getItem(position));
    return view;
}

public void add(ModelType object){
    array.add(object);
}

public void addAll(Collection<? extends ModelType> objects){
    array.addAll(objects);
}

public void addAll(ModelType... objects){
    for(ModelType object : objects){
        array.add(object);
    }
}

public void clear(){
    array.clear();
}

public void insert(ModelType object, int index){
    array.set(index, object);
}

public void remove(ModelType object){
    array.remove(object);
}

public void sort(Comparator<? super ModelType> comparator){
    Collections.sort(array, comparator);
}}

And the row view class:

    public abstract class ListViewRow<ModelType> extends FrameLayout {
ModelType model;
View childView;

public ListViewRow(Activity context, int viewLayout) {
    super(context);
    LayoutInflater inflater = context.getLayoutInflater( );
    childView = inflater.inflate( viewLayout,  this, false );
    addView(childView);
}


public abstract void setModel(ModelType newModel);}

Here's an example child view class that sets a text field and a image field, to show the amount of work in creating the row view:

  public class AdapterRow extends ListViewRow<String> {
TextView tv;
ImageView iv;

public AdapterRow(Activity context) {
    super(context, R.layout.li);
    tv = (TextView)findViewById(R.id.tv);
    iv = (ImageView)findViewById(R.id.iv);
}


public void setModel(String str){
    tv.setText(str);
    iv.setImageResource(R.drawable.ic_launcher);
}}

the code is good but i was trying to add a holder and didn't where should i do this ?

3 Answers3

0

You don't need to use a holder since the views you need to use for showing the model are saved inside your view class.

However, AFAIK this implementation is not so good. since for using the childView item, you make the OS keep reference to its parent ListViewRow item. I wonder why you don't use a recyclerView and ViewHolder instead of listview.

If you want to implement this with listView, here is my suggestion for Holder class and Adapter class.

private abstract class MyHolder<ModelType>
{
    public MyHolder(View itemView) {

        childView= itemView.findViewById(R.id.iv);
        itemView.setTag(this);
    }

    public void showDataInView(ModelType);

    View childView;
}

and the Adapter class:

public class MVCArrayAdapter<ModelType> extends BaseAdapter{
    Activity ctx;
    ArrayList<ModelType> array = new ArrayList<ModelType>();
    Constructor<?> viewConstructor;

    public MVCArrayAdapter(Activity context, String viewClassName) throws NoSuchMethodException, ClassNotFoundException {
        super();
        ctx = context;
        viewConstructor = Class.forName(viewClassName).getConstructor(Activity.class);
    }


    public int getCount() {
        return array.size();
    }

    public Object getItem(int position) {
        return array.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    @SuppressWarnings("unchecked")
    public View getView(int position, View convertView, ViewGroup parent) {
        MyHolder<ModelType> holder = null;
        if (convertView == null) {
            convertView = context.getLayoutInflater().inflate( viewLayout,  this, false );
            holder = new MyHolder(convertView);
            convertView.setTag(holder);
        }
        else
        {
            holder = (MyHolder<ModelType>) convertView.getTag();
        }
        holder.showDataInView((ModelType)getItem(position));
        return convertView;
    }

    public void add(ModelType object){
        array.add(object);
    }

    public void addAll(Collection<? extends ModelType> objects){
        array.addAll(objects);
    }

    public void addAll(ModelType... objects){
        for(ModelType object : objects){
            array.add(object);
        }
    }

    public void clear(){
        array.clear();
    }

    public void insert(ModelType object, int index){
        array.set(index, object);
    }

    public void remove(ModelType object){
        array.remove(object);
    }

    public void sort(Comparator<? super ModelType> comparator){
        Collections.sort(array, comparator);
    }
}
Sina Rezaei
  • 529
  • 3
  • 24
  • Since I don't have enought reputation to comment, I comment here. – Sina Rezaei Jan 04 '16 at 14:53
  • I tried your solution kind of : if (convertView == null) { convertView = context.getLayoutInflater().inflate( viewLayout, this, false ); holder = new MyHolder(convertView); convertView.setTag(holder); } else { holder = (MyHolder) convertView.getTag(); }and didnt work – Carlos Kekwa Jan 07 '16 at 19:48
0

I finally did the same thing that i did above but with some modifications in the MVCArray:

package com.code.utilities;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;

import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class MVCArrayAdapter<ModelType> extends BaseAdapter {
    private final Activity ctx;
    public ArrayList<ModelType> array = new ArrayList<ModelType>();
    private Constructor<?> viewConstructor;

public MVCArrayAdapter(Activity context, String viewClassName)
        throws NoSuchMethodException, ClassNotFoundException {
    super();
    ctx = context;
    viewConstructor = Class.forName(viewClassName).getConstructor(
            Activity.class);

}

@Override
public int getCount() {
    return array.size();
}

public Object getItem(int position) {
    if (position < 0 || position >= array.size()) {
        throw new ArrayIndexOutOfBoundsException();// or something more
    } // specific to your API
    return array.get(position);

}

public long getItemId(int position) {
    return position;
}

@SuppressWarnings("unchecked")
public View getView(int position, View convertView, ViewGroup parent) {
    // ListViewRow<ModelType> view = (ListViewRow<ModelType>) convertView;

    try {
        final ListViewRow<ModelType> view = (ListViewRow<ModelType>) viewConstructor
                .newInstance(ctx);
        final MyHolder holder = new MyHolder(view);
        holder.childView.setModel((ModelType) getItem(position));
        view.setTag(holder);
        return view;
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

    return null;
}

public void add(ModelType object) {
    array.add(object);
}

public void addAll(Collection<? extends ModelType> objects) {
    array.addAll(objects);
}

public void addAll(ModelType... objects) {
    for (ModelType object : objects) {
        array.add(object);
    }
}

public void clear() {
    array.clear();
}

public void insert(ModelType object, int index) {
    array.set(index, object);
}

public void remove(ModelType object) {
    array.remove(object);
}

public void sort(Comparator<? super ModelType> comparator) {
    Collections.sort(array, comparator);
}

@SuppressWarnings("hiding")
public class MyHolder {

    ListViewRow<ModelType> childView = null;

    public MyHolder(ListViewRow<ModelType> view) {
        this.childView = view;
    }

}}

thanks for your help @SinaRezaei it really inspired me !

0

Since I don't have enought reputation to comment, I add my description here. Your final implementation is very bad because it inflates a new view each time a listview item must be shown. It prevents android from using recycled views and creates a new view, which will result in outOfMemory exception for lists with many items containing large data. (e.g. images)

You should create a new instance of view only if your convertView is null, otherwise you should use the recycled view based on view type.

Check this answer for more information

Community
  • 1
  • 1
Sina Rezaei
  • 529
  • 3
  • 24