Search code examples
androidandroid-recyclerviewonclicksharedpreferencesandroid-imageview

Using Shared Preferences in a RecyclerView item Button OnClick


I have a ImageView in my product_list_item.xml as below:

 <ImageView
        android:id="@+id/imgbtn_favorite"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/txt_pdt_desc"
        android:layout_alignParentRight="true"
        android:layout_marginRight="3dp"
        android:background="@null"
        android:clickable="true"
        android:focusable="true"
        android:onClick="starOnClick"
        android:contentDescription="@string/favorites" />

App Output: RecyclerView with Favourites ImageView

I have my OnItemClick and OnItemLongClick in my ProductListFragment class as below:

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    Product product = (Product) parent.getItemAtPosition(position);
    Toast.makeText(activity, product.toString(), Toast.LENGTH_LONG).show();
}

@Override
public boolean onItemLongClick(AdapterView<?> arg0, View view,
        int position, long arg3) {
    ImageView button = (ImageView) view.findViewById(R.id.imgbtn_favorite);

    String tag = button.getTag().toString();
    if (tag.equalsIgnoreCase("grey")) {
        sharedPreference.addFavorite(activity, products.get(position));
        Toast.makeText(activity,
                activity.getResources().getString(R.string.add_favr),
                Toast.LENGTH_SHORT).show();

        button.setTag("red");
        button.setImageResource(R.drawable.heart_red);
    } else {
        sharedPreference.removeFavorite(activity, products.get(position));
        button.setTag("grey");
        button.setImageResource(R.drawable.heart_grey);
        Toast.makeText(activity,
                activity.getResources().getString(R.string.remove_favr),
                Toast.LENGTH_SHORT).show();
    }

    return true;
}

EDIT My ProductListAdapter class

public class ProductListAdapter extends ArrayAdapter<Product> {

private Context context;
List<Product> products;
SharedPreference sharedPreference;

public ProductListAdapter(Context context, List<Product> products) {
    super(context, R.layout.product_list_item, products);
    this.context = context;
    this.products = products;
    sharedPreference = new SharedPreference();
}

private class ViewHolder {
    TextView productNameTxt;
    TextView productDescTxt;
    TextView productPriceTxt;
    ImageView favoriteImg;
}

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

@Override
public Product getItem(int position) {
    return products.get(position);
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.product_list_item, null);
        holder = new ViewHolder();
        holder.productNameTxt = (TextView) convertView
                .findViewById(R.id.txt_pdt_name);
        holder.productDescTxt = (TextView) convertView
                .findViewById(R.id.txt_pdt_desc);
        holder.productPriceTxt = (TextView) convertView
                .findViewById(R.id.txt_pdt_price);
        holder.favoriteImg = (ImageView) convertView
                .findViewById(R.id.imgbtn_favorite);

        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }
    Product product = (Product) getItem(position);
    holder.productNameTxt.setText(product.getName());
    holder.productDescTxt.setText(product.getDescription());
    holder.productPriceTxt.setText(product.getPrice() + "");

    /*If a product exists in shared preferences then set heart_red drawable
     * and set a tag*/
    if (checkFavoriteItem(product)) {
        holder.favoriteImg.setImageResource(R.drawable.heart_red);
        holder.favoriteImg.setTag("red");
    } else {
        holder.favoriteImg.setImageResource(R.drawable.heart_grey);
        holder.favoriteImg.setTag("grey");
    }

    return convertView;
}

/*Checks whether a particular product exists in SharedPreferences*/
public boolean checkFavoriteItem(Product checkProduct) {
    boolean check = false;
    List<Product> favorites = sharedPreference.getFavorites(context);
    if (favorites != null) {
        for (Product product : favorites) {
            if (product.equals(checkProduct)) {
                check = true;
                break;
            }
        }
    }
    return check;
}

@Override
public void add(Product product) {
    super.add(product);
    products.add(product);
    notifyDataSetChanged();
}

@Override
public void remove(Product product) {
    super.remove(product);
    products.remove(product);
    notifyDataSetChanged();
}   
}

EDIT-2

My SharedPreferencesclass have the following:

   public void addFavorite(Context context, Product product) {
    List<Product> favorites = getFavorites(context);
    if (favorites == null)
        favorites = new ArrayList<Product>();
    favorites.add(product);
    saveFavorites(context, favorites);
}

public void removeFavorite(Context context, Product product) {
    ArrayList<Product> favorites = getFavorites(context);
    if (favorites != null) {
        favorites.remove(product);
        saveFavorites(context, favorites);
    }

My complete ProductListFragment class is as below:

public class ProductListFragment extends Fragment implements
    OnItemClickListener, OnItemLongClickListener {

public static final String ARG_ITEM_ID = "product_list";

Activity activity;
ListView productListView;
List<Product> products;
ProductListAdapter productListAdapter;

SharedPreference sharedPreference;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    activity = getActivity();
    sharedPreference = new SharedPreference();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_product_list, container,
            false);
    findViewsById(view);

    setProducts();

    productListAdapter = new ProductListAdapter(activity, products);
    productListView.setAdapter(productListAdapter);
    productListView.setOnItemClickListener(this);
    productListView.setOnItemLongClickListener(this);
    return view;
}

private void setProducts() {

    Product product1 = new Product(1, "Dell XPS", "Dell XPS Laptop", 60000);
    Product product2 = new Product(2, "HP Pavilion G6-2014TX",
            "HP Pavilion G6-2014TX Laptop", 50000);
    Product product3 = new Product(3, "ProBook HP 4540",
            "ProBook HP 4540 Laptop", 45000);
    Product product4 = new Product(4, "HP Envy 4-1025TX",
            "HP Envy 4-1025TX Laptop", 46000);
    Product product5 = new Product(5, "Dell Inspiron",
            "Dell Inspiron Laptop", 48000);
    Product product6 = new Product(6, "Dell Vostro", "Dell Vostro Laptop",
            50000);
    Product product7 = new Product(7, "IdeaPad Z Series",
            "Lenovo IdeaPad Z Series Laptop", 40000);
    Product product8 = new Product(8, "ThinkPad X Series",
            "Lenovo ThinkPad X Series Laptop", 38000);
    Product product9 = new Product(9, "VAIO S Series",
            "Sony VAIO S Series Laptop", 39000);
    Product product10 = new Product(10, "Series 5",
            "Samsung Series 5 Laptop", 50000);

    products = new ArrayList<Product>();
    products.add(product1);
    products.add(product2);
    products.add(product3);
    products.add(product4);
    products.add(product5);
    products.add(product6);
    products.add(product7);
    products.add(product8);
    products.add(product9);
    products.add(product10);
}

private void findViewsById(View view) {
    productListView = (ListView) view.findViewById(R.id.list_product);
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    Product product = (Product) parent.getItemAtPosition(position);
    Toast.makeText(activity, product.toString(), Toast.LENGTH_LONG).show();
}

@Override
public boolean onItemLongClick(AdapterView<?> arg0, View view,
        int position, long arg3) {
    ImageView button = (ImageView) view.findViewById(R.id.imgbtn_favorite);

    String tag = button.getTag().toString();
    if (tag.equalsIgnoreCase("grey")) {
        sharedPreference.addFavorite(activity, products.get(position));
        Toast.makeText(activity,
                activity.getResources().getString(R.string.add_favr),
                Toast.LENGTH_SHORT).show();

        button.setTag("red");
        button.setImageResource(R.drawable.heart_red);
    } else {
        //sharedPreference.removeFavorite(activity, products.get(position));
        button.setTag("grey");
        button.setImageResource(R.drawable.heart_grey);
        Toast.makeText(activity,
                activity.getResources().getString(R.string.remove_favr),
                Toast.LENGTH_SHORT).show();
    }

    return true;
}

Currently the items are marked as Favourites when the user LongClicks (OnItemLongClick) an Item in the RecyclerView..

i implemented the starOnClick in my MainActivity class as below:

public void starOnClick (View view){
    // Toast.makeText(getApplicationContext(),"Star Clicked",Toast.LENGTH_SHORT).show();
}

but i get errors, since i dont know how to get position of the item and saved sharedpreferences in here....

how can i implement the onClick on my ImageView imgbtnFavouriteto mark the items as Favourites


Solution

  • Firstly, I consider it a sub-optimal solution to use SharedPreferences to store this "isFavorite" information. This is a disk operation which will take a performance hit in a highly optimized RecyclerView element. Instead add a property to your Product class which maintains information whether the product is a "Favorite". In my examlpe I will use getIsFavorite() and setIsFavorite(boolean).

    You need to handle the onClick in your Adapter class by setting the setOnClickListener(). Note that you could also just add a onClick for the Item instead of the ImageView ... that will give the user a bigger target to tap.

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.product_list_item, null);
            holder = new ViewHolder();
            holder.productNameTxt = (TextView) convertView
                    .findViewById(R.id.txt_pdt_name);
            holder.productDescTxt = (TextView) convertView
                    .findViewById(R.id.txt_pdt_desc);
            holder.productPriceTxt = (TextView) convertView
                    .findViewById(R.id.txt_pdt_price);
            holder.favoriteImg = (ImageView) convertView
                    .findViewById(R.id.imgbtn_favorite);
    
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
    
        holder.favoriteImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Product prod = products.get(position);
                //toggle the value
                boolean isFavorite = !prod.getIsFavorite();
                prod.setIsFavorite(isFavorite);
    
                if (isFavorite) {
                    holder.favoriteImg.setImageResource(R.drawable.heart_red);
                    holder.favoriteImg.setTag("red");
                } else {
                    holder.favoriteImg.setImageResource(R.drawable.heart_grey);
                    holder.favoriteImg.setTag("grey");
                }
            }
        }); 
    
        Product product = (Product) getItem(position);
        holder.productNameTxt.setText(product.getName());
        holder.productDescTxt.setText(product.getDescription());
        holder.productPriceTxt.setText(product.getPrice() + "");
    
        boolean isItemFavorite = product.getIsFavorite();
    
        if (isItemFavorite) {
            holder.favoriteImg.setImageResource(R.drawable.heart_red);
            holder.favoriteImg.setTag("red");
        } else {
            holder.favoriteImg.setImageResource(R.drawable.heart_grey);
            holder.favoriteImg.setTag("grey");
        }
    
        return convertView;
    }
    

    Now you can get rid of the checkFavoriteItem() method because you are no longer using SharedPreferences.

    So now you do not need these attributes in the ImageView

        android:clickable="true"
        android:focusable="true"
        android:onClick="starOnClick"
    

    Remove them so it can look like this:

    <ImageView
            android:id="@+id/imgbtn_favorite"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@+id/txt_pdt_desc"
            android:layout_alignParentRight="true"
            android:layout_marginRight="3dp"
            android:background="@null"
            android:contentDescription="@string/favorites" />
    




    Edit:

    To add the isFavorite property to your Product class simply add a new class variable:

    private boolean isFavorite = false;
    

    Then add the setter:

    public void setIsFavorite(boolean favorite) { this.isFavorite = favorite; } 
    

    and the getter:

    public boolean getIsFavorite(){ return this.isFavorite; }