Sources

Making template views in Android like a pro

Noräs Salman Noräs Salman |

Tags: #Android #Design #shortcuts #sources

Android is awesome, flexible and hackable when it comes to UI components. A smart developer can make use of existing UI components and reusing components. By that saving time and producing a maintainable healthy code.
In this article, I introduce my way of making reusable components that can also have multiple xml layouts but with the same content.

Making a flexible extendable view class

I start by making a generic extendable class that can be reused and that set a standard how to define a view.

public abstract class AbstractViewHolder {
    
    public View convertView;

    private Context context;

    private DataSetChangeListener dataSetChangeListener;

    public interface DataSetChangeListener {
        public void notifyChange();
    }

    /**
     * @param context         the context.. the activity..etc
     * @param layoutResource  the xml view resource
     * */
    public AbstractViewHolder(Context context, int layoutResource) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.convertView = inflater.inflate(layoutResource, null);
        this.context = context;
    }

    /* binding the inflated view to the convert view (called after constructor) */
    public abstract void bindView();

    /**
     *  building the view using an object
     *  @param object     The object that has the information which will be shown.
     * */
    public abstract void buildView(Object object);

    /**
     * listener for notifying host view
     * @param  dataSetChangeListener   the listener that will publish the event
     * */
    public void setDataSetChangeListener(DataSetChangeListener dataSetChangeListener) {
        this.dataSetChangeListener = dataSetChangeListener;
    }

    /* used in case an array adapter */
    public void notifyDataSetChanged() {
        if (dataSetChangeListener != null)
            dataSetChangeListener.notifyChange();
    }

    /* return the view */
    public View getConvertView() {
        return convertView;
    }
    
    /* return the context */
    public Context getContext() {
        return context;
    }
}

Extending the class

Say we have an article object that will be used in an adapter. The article has a title and an image that we want to show and we already have made an XML view R.layout.item_article_grid.

public class FeedArticleGridViewHolder extends AbstractViewHolder {
    ImageView article_image;
    TextView title_text;

    public FeedArticleGridViewHolder(Context context) {
        super(context, R.layout.item_article_grid);
    }

    @Override
    public void bindView() {
        article_image=convertView.findViewById(R.id.image);
        title_text=convertView.findViewById(R.id.title_text);
    }

    @Override
    public void buildView(Object object) {
        GridArticle article=((GridArticle)object) ;
        title_text.setText(article.title);        Picasso.with(getContext()).load(article.url).fit().centerCrop().into(article_image);
    }
}

The real power of this method

Reusing the same binder and builder we can apply the previous class to bind it a different xml view. For example say the previous view was used in a grid and we want the same content to be viewed in a list. The we don’t need to rewrite the binding and building code. We just extend the grid binder and builder and replace the xml.

public class FeedArticleListViewHolder extends FeedArticleGridViewHolder {

    public ProductListViewHolder(Context context) {
        super(context, R.layout.item_article_list);
    }
}

Using the view holder in an adapter

public class FeedGridAdapter extends ArrayAdapter<GridArticle> {
    
    public FeedGridAdapter(Context context) {
        super(context, 0);
    }
    
    public View getView(int position, View convertView, ViewGroup parent) {

        AbstractViewHolder viewHolder;
        if (convertView == null) {

            viewHolder = new FeedArticleGridViewHolder(getContext());

            viewHolder.bindView();
            convertView = viewHolder.getConvertView();
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (AbstractViewHolder) convertView.getTag();
        }

        viewHolder.setDataSetChangeListener(new AbstractViewHolder.DataSetChangeListener() {
            @Override
            public void notifyChange() {
                notifyDataSetChanged();
            }
        });
      
        viewHolder.buildView(getItem(position));
        return convertView;
    }
    
}

About the author

Noräs Salman

"Senior Software Engineer. MSc in Computer systems and Networks with big interest in security. Loves to play with Android code and does security research for fun and profit. Speaks 4 languages and codes in much more."

Related articles

Tags: #Android #Design #shortcuts #sources




Copyright © 2019 - nindoda.com