Create a Generic Adapter

Asked

Viewed 120 times

3

Good evening! Dear friends, I have a question , has anyone ever come across the situation of having several lists but with similar information? a simple listing of information coming from the service? I would like to know if it is possible to create a generic Adapter. I thank you already

  • Assuming you have an application, for example customer and employee registration, that have similar features, you want to create an Adapter that fits both?

  • Exactly for one or more activities!

  • I believe you can do that with inheritance

  • The line layout is always the same?

2 answers

2

Yes it is possible.

However you will have to write a Viewholder for each type of layout of the item, a Viewholderfactory and your Model will have to implement an interface.

Viewholder is required to connect the Model to the Views.
The Viewholderfactory for the Adapter to build the Viewholder it will use.
The interface, which the Model implements, is used to indicate, through the parameter viewType of the method onCreateViewHolder(), what layout to use to create Viewholder.

For all this to work it is necessary to create some abstractions:

  • Interface Typeprovider, to be implemented by Model

    public interface TypeProvider {
        int type(ViewHolderFactory viewHolderFactory);
    }
    
  • Genericviewholder, abstract class of which each Viewholder should inherit.

    public abstract class GenericViewHolder<T> extends RecyclerView.ViewHolder{
        public GenericViewHolder(View itemView) {
            super(itemView);
        }
    
        public abstract void bind(T item);
    }
    
  • Interface Viewholderfactory, each type of Viewmodel will be built by the corresponding implementation of this class.

    public interface ViewHolderFactory {        
        int type();
        GenericViewHolder createViewHolder(View parent);
    }
    

It is these abstractions that will allow Adapter to work with any type of data(Model) and Viewholder.

Implementation of the Adapter:

public class GenericRecyclerAdapter extends RecyclerView.Adapter<GenericViewHolder> {

    private ArrayList<TypeProvider> items;
    private ViewHolderFactory viewHolderFactory;

    public GenericRecyclerAdapter(ArrayList<TypeProvider> items, ViewHolderFactory viewHolderFactory){

        this.items = items;
        this.viewHolderFactory = viewHolderFactory;
    }

    @Override
    public GenericViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext())
                                  .inflate(viewType, parent, false);
        return viewHolderFactory.createViewHolder(view);
    }

    @Override
    public void onBindViewHolder(GenericViewHolder holder, int position) {
        holder.bind(items.get(position));
    }

    @Override
    public int getItemViewType(int position) {
        return items.get(position).type(viewHolderFactory);
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

}

The infrastructure is made.

Example of use.

  • Model, in this example represents an image and its name.

    public class Model implements TypeProvider {
    
        private int imageId;
        private String imageName;
    
        public Model(int imageId, String imageName){
            this.imageId = imageId;
            this.imageName = imageName;
        }
    
        @Override
        public int type(ViewHolderFactory viewHolderFactory) {
            // Ao delegar para o viewHolderFactory a obtenção do Layout
            // evita-se que o model dependa do framework Android, neste caso da classe R.
            return viewHolderFactory.type();
        }
    
        public int getImageId() {
            return imageId;
        }
    
        public String getImageName() {
            return imageName;
        }
    }
    
  • Viewholder, follows the classic implementation: in the constructor you get references to layout views and in the method bind() the model values are assigned to the respective views:

    public class ModelViewHolder extends GenericViewHolder<Model> {
    
        //A ser usado pelo ViewHolderFactory para, através do model,
        //indicar, no método onCreateViewHolder(), qual o layout a usar
        public static final int LAYOUT = R.layout.item_view;
    
        private ImageView mImageView;
        private TextView mTextView;
    
        public ModelViewHolder(View itemView) {
            super(itemView);
            mImageView = (ImageView) itemView.findViewById(R.id.image);
            mTextView = (TextView)itemView.findViewById(R.id.text);
        }
    
        @Override
        public void bind(Model item) {
            mTextView.setText(item.getImageName());
            mImageView.setImageResource(item.getImageId());
        }
    }
    
  • Viewholderfactory

    public class ModelViewHolderFactory implements ViewHolderFactory {
        @Override
        public int type() {
            return ModelViewHolder.LAYOUT;
        }
    
        @Override
        public GenericViewHolder createViewHolder(View parent) {
            return new ModelViewHolder(parent);
        }
    }
    
  • Gathered all in Activity

    public class GenericAdapterActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
            ArrayList<TypeProvider> items = new ArrayList<>();
    
            items.add(new Model(R.mipmap.ic_launcher, "item1"));
            items.add(new Model(R.mipmap.ic_launcher, "item2"));
            items.add(new Model(R.mipmap.ic_launcher, "item3"));
            items.add(new Model(R.mipmap.ic_launcher, "item4"));
            items.add(new Model(R.mipmap.ic_launcher, "item5"));
    
            recyclerView.setHasFixedSize(true);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
    
            ModelViewHolderFactory modelViewHolderFactory = new ModelViewHolderFactory();
    
            GenericRecyclerAdapter adapter = new GenericRecyclerAdapter(items, modelViewHolderFactory);
            recyclerView.setAdapter(adapter);
        }
    }
    

It seems like a lot of work, however it is almost as much as having to make several Adapters. The extra work is only the creation of abstractions, but they are created only once. Viewholder and Model must always be created, whatever the approach.
However, this "is more object oriented" than having multiple Adapters.

Source of inspiration:

  • Writing Better Adapters

    Note: The post indicates a link for an improved implementation that allows the same list to have items of different data types and layouts.

  • Thanks ramaral! I understood the logic that was used! today I will test and give you a feedback

0

One option would be to create a Pessoa.java class and perform an instantiation in the other classes, for example Client and Employee, in case you would make an Adapter that would have the common values of the classes. Example:

Parent class:

public class Pessoa {
    private String nome;

    public Pessoa() {
    }

    public Pessoa(String nome) {
        this.nome = nome;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public String toString() {
        return "Pessoa{" +
                "nome='" + nome + '\'' +
                '}';
    }
}

Child classes:

public class Funcionario {
    private double salario;
    private Pessoa p;

    public Funcionario() {
    }

    public Funcionario(double salario, Pessoa p) {
        this.salario = salario;
        this.p = p;
    }

    public double getSalario() {
        return salario;
    }

    public void setSalario(double salario) {
        this.salario = salario;
    }

    public Pessoa getP() {
        return p;
    }

    public void setP(Pessoa p) {
        this.p = p;
    }

    @Override
    public String toString() {
        return "Funcionario{" +
                "salario=" + salario +
                ", p=" + p +
                '}';
    }
}

public class Cliente {
    private int idade;
    private Pessoa p;

    public Cliente() {
    }

    public Cliente(int idade, Pessoa p) {
        this.idade = idade;
        this.p = p;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public Pessoa getP() {
        return p;
    }

    public void setP(Pessoa p) {
        this.p = p;
    }

    @Override
    public String toString() {
        return "Cliente{" +
                "idade=" + idade +
                ", p=" + p +
                '}';
    }
}

Adapter:

public class Adapter extends BaseAdapter{
    private Context contexto;

    private ArrayList<Pessoa> ps;
    private LayoutInflater inflater;

    public TextView tvNome;

    public Adapter(Context contexto, ArrayList<Pessoa> ps) {
        this.contexto = contexto;
        this.ps = ps;
        inflater = LayoutInflater.from(contexto);
    }

    public void notifyDataChanged() {
        super.notifyDataSetChanged();
    }

    public void adicionar(Pessoa p) {
        ps.add(p);
    }

    public void remover(Pessoa p) {
        ps.remove(p);
    }

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

    @Override
    public Object getItem(int posicao) {
        return ps.get(posicao);
    }

    @Override
    public long getItemId(int posicao) {
        return posicao;
    }

    @Override
    public View getView(int posicao, View convertView, ViewGroup parent) {
        Pessoa p = ps.get(posicao);

        if(convertView == null) {
            convertView = inflater.inflate(R.layout.linha, null);
        }

        //Instancia os objetos
        tvNome = (TextView) convertView.findViewById(R.id.tv_nome);

        tvNome.setText(p.getNome());

        return convertView;
    }
}

I made an extremely simple example just to show that possibility, any doubt, just ask

  • Thanks even William! I will implement and any doubt I speak to you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.