Recycleview Click and Child View Click - android

I am using recycler view for products. I want to display product description on recycler item click.
I also put a button and checkbox(favorite) on recyclerview row.
Now i required to get click event of all, means i want recyclerview item click and child control click.
My layout is look like this :
RecyclerView Touch event
productRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
final int action = e.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
if (actionMasked == MotionEvent.ACTION_DOWN) {
return false;
} else if (actionMasked == MotionEvent.ACTION_UP) {
HomeActivity.productclicked = (productDatas.get
(2));
HomeActivity.loadView(new SingleProductFragment(), "SingleProduct");
return false; //intercepted by the viewgroup and passed down to child
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
In Adapter Add to Cart Button click
viewHolder.cart_action.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UserCart.addProductToCart(Integer.parseInt(view.getTag().toString()));
HomeActivity.increaseCartCount();
}
});
If i didn't implement touchlistener on recyclerview then every button will work else it didn't work.
Basically i want to know how to implement click on recyclerview item and its child
For information i also using Scroll Listener over RecyclerView. But i thought it didn't affect to click events
My Adapter Class
package net.techdesire.swarnasikha.adapter_package;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.facebook.common.soloader.SoLoaderShim;
import com.facebook.common.util.UriUtil;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import net.techdesire.swarnasikha.R;
import net.techdesire.swarnasikha.activity_package.HomeActivity;
import net.techdesire.swarnasikha.data_package.ProductData;
import net.techdesire.swarnasikha.data_package.UserCart;
import net.techdesire.swarnasikha.fragments_package.SingleProductFragment;
import java.util.ArrayList;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Created by Naitik Kundalia on 2/28/2017.
*/
public class ProductDataAdapter extends RecyclerView.Adapter<ProductDataAdapter
.ProductViewHolder> {
private ArrayList<ProductData> productDataArrayList;
private Context context;
public ProductDataAdapter(Context context, ArrayList<ProductData> countries) {
this.context=context;
this.productDataArrayList = countries;
}
#Override
public ProductDataAdapter.ProductViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_product, viewGroup,
false);
return new ProductViewHolder(view);
}
#Override
public void onBindViewHolder(ProductViewHolder viewHolder,final int position) {
try {
ProductData currentProduct = productDataArrayList.get(position);
viewHolder.product_name.setText(currentProduct.getName());
viewHolder.product_image.setImageURI(currentProduct.getImages().get(0).getSrc());
viewHolder.cart_action.setTag(currentProduct.getId());
viewHolder.cart_action.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UserCart.addProductToCart(Integer.parseInt(view.getTag().toString()));
HomeActivity.increaseCartCount();
}
});
viewHolder.container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Clicked", Toast.LENGTH_SHORT).show();
HomeActivity.productclicked=productDataArrayList.get(position);
HomeActivity.loadView(new SingleProductFragment(),"SingleProduct");
}
});
}
catch(Exception ex)
{
Toast.makeText(context, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public int getItemCount() {
return productDataArrayList.size();
}
public class ProductViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public View container;
public TextView addedtocart;
public TextView product_name;
SimpleDraweeView product_image;
Button cart_action;
public ProductViewHolder(View view) {
super(view);
container=view;
product_name = (TextView)view.findViewById(R.id.row_product_name_textview);
addedtocart = (TextView)view.findViewById(R.id.row_added_to_cart_textview);
product_image=(SimpleDraweeView) view.findViewById(R.id.row_product_imageview);
cart_action=(Button)view.findViewById(R.id.row_cart_action_button);
//view.setOnClickListener(this);
}
public void onClick(View v)
{
Toast.makeText(context, "View Clicked", Toast.LENGTH_SHORT).show();
}
}
}

Related

Why does RecyclerView not get updated from the LiveData in the Viewmodel?

I have a fragment (Inventory Fragment) that displays some CardView objects in a RecyclerView. These objects get their data from an Adapter after the data has been received from the ViewModel. Inside the adapter, there are certain functions that can change the Livedata. All of these functions first open another Fragment (Food Editor), and this where the new data is set to the ViewModel.
My problem is that even after this, the RecyclerView does not get the new object. I used notifyDataSetChanged(). What am I doing wrong? Is there an easier way to achieve what I am trying to do (Add, Delete, Modify and such)?
Inventory Fragment:
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
public class InventoryFragment extends Fragment {
//GLOBAL VARIABLES
RecyclerView recyclerView;
FoodAdapter foodAdapter;
FloatingActionButton add_button;
FrameLayout frameLayout;
FoodViewModel foodViewModel;
//FOOD LIST
private List<Food> foodList;
public InventoryFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_inventory, container, false);
//GETTING THE FOOD VIEW MODEL
foodViewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(FoodViewModel.class); //TODO:HERE
foodList = foodViewModel.getFoods().getValue();
foodAdapter = new FoodAdapter(foodList);
recyclerView=v.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(foodAdapter);
//SETTING THE FOOD VIEW MODEL
foodViewModel.getFoods().observe(getActivity(), new Observer<List<Food>>() {
#Override
public void onChanged(List<Food> foods) {
foodAdapter.setFoods(foods);
foodList=foods;
foodAdapter.notifyDataSetChanged(); //TODO: MAKE THIS BETTER
}
});
//setting up the frameLayout
frameLayout = v.findViewById(R.id.food_editor_frame);
//setting up the Add button
add_button=v.findViewById(R.id.add_button);
add_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //for new food addition to list
openFoodEditorFragment(-1);
}
});
foodAdapter.setOnFoodcardClickListener(new FoodAdapter.OnFoodcardClickListener() {
#Override
public void deleteFood(int position) { //code that deletes current food
foodViewModel.delete(foodList.get(position));
foodAdapter.notifyItemRemoved(position);
}
#Override
public void onEdit(int position) { //code that runs the edit of each food
openFoodEditorFragment(position);
foodAdapter.notifyItemChanged(position);
}
#Override
public void decrease(int position) {
foodList.get(position).decrease();
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
#Override
public void increase(int position) {
foodList.get(position).increase();
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
#Override
public void setSeekBar(int position,int progress) {
foodList.get(position).setQuantity(progress);
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
});
return v;
}
public void openFoodEditorFragment(int position){ //position = -1 for new, and an integer (position) for edit
FoodEditorFragment foodEditorFragment;
switch(position){
case -1:
foodEditorFragment = new FoodEditorFragment(foodViewModel);
break;
default:
foodEditorFragment = new FoodEditorFragment(foodList.get(position),foodViewModel);
break;
}
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
}
RecyclerView's adapter:
package com.coffeetech.kittycatch;
import android.app.Application;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
//VARIABLE THAT CONTAINS THE FOOD LIST (array list)
public List<Food> foods;
int size;
private OnFoodcardClickListener onFoodcardClickListener;
//listener interface
public interface OnFoodcardClickListener{
void deleteFood(int position);
void onEdit(int position);
void decrease(int position);
void increase(int position);
void setSeekBar(int position, int progress);
}
public void setOnFoodcardClickListener(OnFoodcardClickListener activity){ //this is called in MainActivity
onFoodcardClickListener=activity;
}
public FoodAdapter(List<Food>foods){
this.foods=foods;
}
public static class FoodViewHolder extends RecyclerView.ViewHolder{
//VARIABLES FOR EACH WIDGET IN FOODCARD
TextView name,quantity; //to modify according to current food
ImageButton decreaseButton,increaseButton; //to hide or show
SeekBar seekbar; //according to current type
ImageButton deleteButton,editButton;
public FoodViewHolder(#NonNull View itemView, final OnFoodcardClickListener listener) {//'itemView' is the card
super(itemView);
name=itemView.findViewById(R.id.name);
quantity=itemView.findViewById(R.id.quantity);
decreaseButton=itemView.findViewById(R.id.decrease_button);
increaseButton=itemView.findViewById(R.id.increase_button);
seekbar=itemView.findViewById(R.id.seekbar);
deleteButton=itemView.findViewById(R.id.delete_button);
editButton=itemView.findViewById(R.id.edit_button);
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.onEdit(position);
}
}
}
});
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.deleteFood(position);
}
}
}
});
decreaseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.decrease(position);
}
}
}
});
increaseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.increase(position);
}
}
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.setSeekBar(position,seekBar.getProgress());
}
}
}
});
}
}
#NonNull
#Override
public FoodViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.foodcard, parent, false); //inflating Foodcard
FoodViewHolder vw = new FoodViewHolder(v,onFoodcardClickListener);
return vw;
}
#Override
public void onBindViewHolder(#NonNull FoodViewHolder holder, int position) { //'holder' is the foodcard here
Food currentFood=foods.get(position);
holder.name.setText(currentFood.getName());
holder.quantity.setText(String.valueOf(currentFood.getQuantity()));
holder.seekbar.setProgress(currentFood.getQuantity());
//code to hide or show certain widgets based on food type
if(currentFood.getType()==0){ //for discrete food
holder.increaseButton.setVisibility(View.VISIBLE);
holder.decreaseButton.setVisibility(View.VISIBLE);
holder.quantity.setVisibility(View.VISIBLE);
holder.seekbar.setVisibility(View.GONE);
}else{// for continuous food
holder.increaseButton.setVisibility(View.GONE);
holder.decreaseButton.setVisibility(View.GONE);
holder.quantity.setVisibility(View.GONE);
holder.seekbar.setVisibility(View.VISIBLE);
}
}
#Override
public int getItemCount() {
return size;
}
//FUCNTION TO GET LIVE DATA HERE
public void setFoods (List<Food> foods){
this.foods=foods;
notifyDataSetChanged();
}
}
Food Editor Fragment:
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FoodEditorFragment extends Fragment {
private TextView name,quantity,min_quantity;
private ImageButton save,cancel;
private RadioGroup radioGroup;
protected int t,mode;
protected Food food;
FoodViewModel foodViewModel;
public FoodEditorFragment() {
// Required empty public constructor
}
public FoodEditorFragment (Food food, FoodViewModel foodViewModel){
this.food=food;
this.foodViewModel=foodViewModel;
mode=1;
}
public FoodEditorFragment (FoodViewModel foodViewModel){
this.foodViewModel=foodViewModel;
this.food = new Food();
mode=0;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_food_editor, container, false);
name=view.findViewById(R.id.name_editor);
quantity=view.findViewById(R.id.quantity_editor);
min_quantity=view.findViewById(R.id.min_quantity_editor);
save=view.findViewById(R.id.save_button_editor);
cancel=view.findViewById(R.id.cancel_button_editor);
radioGroup=view.findViewById(R.id.radioGroup_editor);
if (mode==1){ //for editing Food
//CODE TO SETUP EDITOR ACCORDING TO INITIAL DETAILS
name.setText(food.getName());
quantity.setText(String.valueOf(food.getQuantity()));
min_quantity.setText(String.valueOf(food.getMin_quantity()));
t=food.getType();
if(t==0){//for discrete food
radioGroup.check(R.id.discrete_radioButton);
}else{//for cont food
radioGroup.check(R.id.cont_radioButton);
}
}
setButtons();
return view;
}
public void setButtons(){
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //USE BELOW 'food' TO PASS NEW DATA TO ACTIVITY
try {
if ((!name.getText().toString().isEmpty()) && ((radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) || (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton))) {
food.setName(name.getText().toString());
food.setQuantity(Integer.parseInt(quantity.getText().toString()));
food.setMin_quantity(Integer.parseInt(min_quantity.getText().toString()));
if (radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) {
food.setType(0);
} else if (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton) {
food.setType(1);
}
switch (mode){
case 0:
foodViewModel.insert(food);
break;
case 1:
foodViewModel.update(food);
break;
}
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
} else {
throw new Exception();
}
}catch (Exception e){
Toast.makeText(getContext(),"Please set all details",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //CODE IF USER PRESSES ON CANCEL
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
}
});
}
}
ViewModel I am using:
package com.coffeetech.kittycatch;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.ArrayList;
import java.util.List;
public class FoodViewModel extends AndroidViewModel {
private FoodRepository repository;
private LiveData<List<Food>> foods;
public FoodViewModel(#NonNull Application application) {
super(application);
repository = new FoodRepository(application);
foods=repository.getAll();
}
public void insert(Food food){
repository.insert(food);
}
public void update(Food food){
repository.update(food);
}
public void delete(Food food){
repository.delete(food);
}
public void deleteAll(){
repository.deleteAll();
}
public LiveData<List<Food>> getFoods(){
return foods;
}
public LiveData<List<Food>> getBuying () {return repository.getBuying();}
}
In FoodAdapter's getItemCount() method, You set itemcount static. You have to change it to foods.size()

How to use a ViewModel outside of onCreate()?

I have an Activity with a RecyclerView which display Livedata from a room database.
My aim is to start a new Activity with more data from the room database when the user is clicking on the corresponding item in the RecyclerView.
For that I overwrote the onClick() method in the adapter of the RecylcerView. Each object of the RecyclerView has a Id, I need that Id to get the corresponding data from the database. So I passed the Id from the Adapter to the Activity.
To search an element by Id in the database that I need the ViewModel object in the MainAcitivty. It is initialized in the onCreate() of the Activity. The method I called in the Adapter is outside the onCreate() and I get a null object reference exception when I try to use it.
How can I use the ViewModel outside of the onCreate() method of the Activity? Or is there another way to search for the element in the database?
Thank you!
The Adapter class:
In the onClick() method is the relevant part.
package com.example.fillmyplate.activities;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.fillmyplate.R;
import com.example.fillmyplate.entitys.Recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class RecipeAdapter extends RecyclerView.Adapter<RecipeAdapter.RecipeViewHolder> {
private static final String TAG = "RecipeAdapter";
private List<Recipe> mRecipes = new ArrayList<>();
private LayoutInflater mInflater;
private Context mContext;
private MainActivity mainActivity = new MainActivity();
private static int backGroundIndex = 0;
class RecipeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView recipeTitleItemView;
ImageView imageView;
public RecipeViewHolder(View itemView) {
super(itemView);
recipeTitleItemView = itemView.findViewById(R.id.name);
imageView = itemView.findViewById(R.id.card_image_view);
Log.d(TAG, "RecipeViewHolder: index " + backGroundIndex);
if (backGroundIndex == 0) {
imageView.setImageResource(R.drawable.background_green);
backGroundIndex++;
} else if (backGroundIndex == 1 ) {
imageView.setImageResource(R.drawable.background_red);
backGroundIndex++;
} else if (backGroundIndex == 2 ) {
imageView.setImageResource(R.drawable.background_blue);
backGroundIndex = 0;
}
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
// This should be the mistake.
mainActivity.startKnownRecipeActivity(position);
}
}
public RecipeAdapter(Context context) {
mInflater = LayoutInflater.from(context);
this.mContext = context;
}
#NonNull
#Override
public RecipeAdapter.RecipeViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// Inflate an item view
View mRecipeTitleView = mInflater.inflate(
R.layout.recipe_list_row, parent, false);
return new RecipeViewHolder(mRecipeTitleView);
}
// Get data into the corrsponding views
#Override
public void onBindViewHolder(RecipeAdapter.RecipeViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder: " + position);
Recipe currentRecipe = mRecipes.get(position);
Log.d(TAG, "onBindViewHolder: setText " + currentRecipe);
holder.recipeTitleItemView.setText(currentRecipe.getTitle());
}
#Override
public int getItemCount() {
return mRecipes.size();
}
public void setRecipes(List<Recipe> recipes) {
this.mRecipes = recipes;
Log.d(TAG, "setRecipes: notifydataChanged" );
notifyDataSetChanged();
}
}
MainActivity:
package com.example.fillmyplate.activities;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.media.Image;
import android.os.Build;
import android.os.Bundle;
import com.example.fillmyplate.R;
import com.example.fillmyplate.entitys.Recipe;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.cardview.widget.CardView;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainAcitivity";
private static final int NEW_RECIPE_ACTIVITY_REQUEST_CODE = 1;
private RecyclerView mRecyclerView;
private RecipeViewModel mRecipeViewmodel;
private RecyclerView.LayoutManager layoutManager;
//private final List<String> mTitleList = new LinkedList<>();
//NEU for adapter
private List<String> recipeDataList = new ArrayList<>();
RecipeRoomDatabase db;
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// RECYCLER VIEW STUFF
mRecyclerView = findViewById(R.id.recycler_view1);
mRecyclerView.setHasFixedSize(true);
// user linerar layout manager
layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
// specify an adapter
final RecipeAdapter recipeAdapter = new RecipeAdapter(this);
//mAdapter = new RecipeAdapter(this, mTitleList);
mRecyclerView.setAdapter(recipeAdapter);
mRecipeViewmodel = ViewModelProviders.of(this).get(RecipeViewModel.class);
mRecipeViewmodel.getAllRecipes().observe(this, new Observer<List<Recipe>>() {
#Override
public void onChanged(List<Recipe> recipes) {
Log.d(TAG, "onChanged: " + recipes.toString());
for (Recipe rec : recipes) {
Log.d(TAG, "onChanged: " + rec.getTitle());
Log.d(TAG, "onChanged: recipe id " + rec.getUid());
}
recipeAdapter.setRecipes(recipes);
}
});
// DB
db = Room.databaseBuilder(getApplicationContext(), RecipeRoomDatabase.class, "appdb").build();
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, AddRecipeActivity.class);
startActivityForResult(intent, NEW_RECIPE_ACTIVITY_REQUEST_CODE);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: ");
if (requestCode == NEW_RECIPE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
Log.d(TAG, "onActivityResult: " + data.getStringExtra(AddRecipeActivity.EXTRA_REPLY));
// mTitleList.add(data.getStringExtra(AddRecipeActivity.EXTRA_REPLY));
Recipe rec = new Recipe(data.getStringExtra(AddRecipeActivity.EXTRA_REPLY));
mRecipeViewmodel.insert(rec);
} else {
Toast.makeText(
getApplicationContext(),
"saved",
Toast.LENGTH_LONG).show();
}
}
public void startKnownRecipeActivity(int position) {
Log.d(TAG, "startKnownRecipeActivity: Position " + position);
LiveData<List<Recipe>> recipe = mRecipeViewmodel.findById(position);
if (recipe.getValue().size() > 1) {
Log.d(TAG, "startKnownRecipeActivity: Error database found more than one recipe.");
} else {
Log.d(TAG, "startKnownRecipeActivity: Start activity with recipe " + recipe.getValue().get(0).getTitle());
}
}
}
The thing you need to do is to use a call back to send position back to activity.
To make sure that view position is correct you need to override 3 functions in RecyclerView Adapter:
#Override
public int getItemCount() {
return filteredUsers.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
For the Callback just create an Interface:
public interface AdapterListener {
void onClick(int id);
void onClick(ViewModel object);
}
Make a method in your Recycler Adapter:
private AdapterListener adapterListener;
public void setAdapterListener(AdapterListener mCallback) {
this.adapterListener = mCallback;
}
Implement this Interface on your Activity then you will get both methods of the interface.
public class MainActivity extends AppCompatActivity implements AdapterListener{
Register the listener by calling the setAdapterListener method in your activity after the initialization of the RecyclerView
adapterObject.setAdapterListener(MainActivity.this);
Then the last thing you need to do is call interface method in your item onClickListener, where u can either pass the complete model or just the id of the model
adapterListener.onClick(modelObject.getId());
OR
adapterListener.onClick(modelObject);

Firebase RecyclerView Adapter Nullpointer exception [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I'm trying to do click on single item which is gated by Firebase recyclerview adapter by I getting some run time error.
This is my code for ImageViewHolder.class and I'm getting NullPOinter Exception.
This exception is caused on mClickListener so please give me some solution for this problem, I'm not getting proper idea about it.
package com.humbingo.asthanews.Settings;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import com.humbingo.asthanews.R;
import com.squareup.picasso.Callback;
import com.squareup.picasso.NetworkPolicy;
import com.squareup.picasso.Picasso;
public class ImageViewHolder extends RecyclerView.ViewHolder {
private static final String TAG = "Firebase";
private View mView;
public Button shareBtn;
public Context context;
public ImageView imageView;
private ImageViewHolder.ClickListener mClickListener;
public ImageViewHolder(View itemView) {
super(itemView);
mView = itemView;
shareBtn = mView.findViewById(R.id.btnShare);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mClickListener.onItemClick(v, getAdapterPosition());
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mClickListener.onItemLongClick(v, getAdapterPosition());
return true;
}
});
}
public void setTitle(String title) {
TextView mPostTitle = mView.findViewById(R.id.postTitle);
Log.d(TAG, "This is Title||-- " + title);
mPostTitle.setText(title);
}
public void setDesc(String desc) {
TextView mPostDesc = mView.findViewById(R.id.postDesc);
mPostDesc.setText(desc);
Log.d(TAG, "This is Description||-- " + desc);
}
public void setImage(final Context ctx, final String imageStr) {
imageView = mView.findViewById(R.id.postImg);
// Picasso.with(ctx).load(imageStr).into(imageView);
Picasso.with(ctx).load(imageStr).networkPolicy(NetworkPolicy.OFFLINE).into(imageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Log.e(TAG, "setImage: Error Message ");
Picasso.with(ctx).load(imageStr).into(imageView);
}
});
}
//Interface to send callbacks...
public interface ClickListener{
public void onItemClick(View view, int position);
public void onItemLongClick(View view, int position);
}
public void setOnClickListener(ImageViewHolder.ClickListener clickListener){
mClickListener = clickListener;
}
}
one simply cannot call interface methods - but has to implement them.
I mean, that interface by itself appears to be useless complexity - because the framework already provides the interfaces one has to implement (which does not mean "adding some more interfaces").
it rather should look about like that ...
itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view, int resId) {
...
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
...
return true;
}
});

OnClickListener RecyclerView List of buttons

I have a RecyclerView and each item is a button. Each button will call the same activity by passing a different parameter to this activity.
I tried many solutions found on the web but none of them had worked for me.
Here is my adapter :
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import java.util.List;
public class FormAdapter extends RecyclerView.Adapter<FormAdapter.FormViewHolder> {
private List<Form> forms;
private int rowLayout;
private Context context;
public class FormViewHolder extends RecyclerView.ViewHolder {
LinearLayout formsLayout;
Button form;
public FormViewHolder(View v) {
super(v);
formsLayout = (LinearLayout) v.findViewById(R.id.forms_layout);
form = (Button) v.findViewById(R.id.formButton);
}
}
public FormAdapter(List<Form> forms, int rowLayout, Context context) {
this.forms = forms;
this.rowLayout = rowLayout;
this.context = context;
}
#Override
public FormAdapter.FormViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
return new FormViewHolder(view);
}
#Override
public void onBindViewHolder(FormViewHolder holder, final int position) {
holder.form.setText(forms.get(position).getSubject());
}
#Override
public int getItemCount() {
return forms.size();
}
}
A form is represented by the following class :
public class Form {
private final String subject;
private final int idForm;
public Form(String subject,int idForm)
{
this.idForm=idForm;
this.subject=subject;
}
public String getSubject()
{
return subject;
}
public int getIdForm()
{
return idForm;
}
}
And here is my MainActivity :
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int idCreator = 1;
private FormAdapter formAdapter;
private List<Form> forms;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Main activity");
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerViewForm);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Formable formService =
ApiClient.getClient().create(Formable.class);
Call<List<Form>> call = formService.getForms(idCreator);
call.enqueue(new Callback<List<Form>>() {
#Override
public void onResponse(Call<List<Form>> call, Response<List<Form>> response) {
forms = response.body();
formAdapter=new FormAdapter(forms, R.layout.one_form, getApplicationContext());
recyclerView.setAdapter(formAdapter);
}
#Override
public void onFailure(Call<List<Form>> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
}
I have my buttons on screen but I don't understand how to make them call the activity "QuestionsActivity" with a parameter "idForm" that I know.
Here is the MainActivity when I run the app
Thanks in advance for your help
You can get item data by following way when you click on recyclerview item:
Create Interface in your adapter and use it in your activity:
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
Now Your code look like below:
FormAdapter.java
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import java.util.List;
public class FormAdapter extends RecyclerView.Adapter<FormAdapter.FormViewHolder> {
private List<Form> forms;
private int rowLayout;
private Context context;
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
public class FormViewHolder extends RecyclerView.ViewHolder {
LinearLayout formsLayout;
Button form;
public FormViewHolder(View v) {
super(v);
formsLayout = (LinearLayout) v.findViewById(R.id.forms_layout);
form = (Button) v.findViewById(R.id.formButton);
}
}
public FormAdapter(List<Form> forms, int rowLayout, Context context) {
this.forms = forms;
this.rowLayout = rowLayout;
this.context = context;
}
#Override
public FormAdapter.FormViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
return new FormViewHolder(view);
}
#Override
public void onBindViewHolder(FormViewHolder holder, final int position) {
holder.form.setText(forms.get(position).getSubject());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(mListener!=null)
{
mListener.onItemClick(view,position);
}
}
});
}
#Override
public int getItemCount() {
return forms.size();
}
public void setOnItemClick(OnItemClickListener listener)
{
this.mListener=listener;
}
}
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import com.newstory.android.R;
import com.newstory.android.activity.FormAdapter;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int idCreator = 1;
private FormAdapter formAdapter;
private List<Form> forms;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Main activity");
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerViewForm);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Formable formService =
ApiClient.getClient().create(Formable.class);
Call<List<Form>> call = formService.getForms(idCreator);
call.enqueue(new Callback<List<Form>>() {
#Override
public void onResponse(Call<List<Form>> call, Response<List<Form>> response) {
forms = response.body();
formAdapter=new FormAdapter(forms, R.layout.one_form, getApplicationContext());
recyclerView.setAdapter(formAdapter);
setOnItemListener();
}
#Override
public void onFailure(Call<List<Form>> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
public void setOnItemListener(){
if(formAdapter!=null)
{
formAdapter.setOnItemClick(new FormAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Form clickedForm=forms.get(position);
// You can call QuestionsActivity here
//Now you can access [Form] data
Log.d("getIdForm->",String.valueOf(clickedForm.getIdForm()))
}
});
}
}
}
I hope it's helps you.
Do this way :
form.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// do something when the form is clicked
context.startActivity(new Intent(context, YourActivity.class)
.putExtra("idForm", someValue));
}
});
In your adapter's onBindViewHolder method, assign a click listener to the button view element, so it would look something like this:
#Override
public void onBindViewHolder(FormViewHolder holder, final int position {
holder.form.setText(forms.get(position).getSubject());
holder.form.setOnClickListener(v -> {
startQuestionsWithId(forms.get(position).getIdForm);
});
}
And then, your startQuestionsWithIdmethod would typically be like:
private void startQuestionsWithId(int idForm) {
Intent intent = new Intent(context, QuestionsActivity.class);
intent.putExtra("id_form", idForm);
context.startActivity(intent);
}

Checkbox,ImageView and GridView

I have a GridView where each grid item consists of an ImageView and a Checkbox. Now, when I select one checkbox, lets say number 5, another checkbox like number 12 gets selected automatically. Similar for deselection.
I cannot figure out why this is happening. Any help will be appreciated.
package com.example.vasylpaliy.mediaview;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.Toast;
import com.adapter.ImageAdapter;
import java.io.File;
import java.util.ArrayList;
public class ImageSelecter extends AppCompatActivity
implements AdapterView.OnItemClickListener {
private GridView view;
private boolean colNum=false;
private ArrayList<String> imagePaths;
private final static int IMAGE_PATH_REQUEST=1;
private ImageAdapter imageAdapter;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.image_selector);
view=(GridView)findViewById(R.id.gridView);
imagePaths=getIntent().getStringArrayListExtra("images");
getSupportActionBar().setHomeButtonEnabled(true);
if(imagePaths!=null){
setAdapter(false);
setMultiChoiceMode();
view.setOnItemClickListener(this);
}
setResult(RESULT_CANCELED);
}
private void setMultiChoiceMode(){
view.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
view.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
private ArrayList<String> imageItems=new ArrayList<String>();
private boolean isChecked=false;
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
imageItems.add(imagePaths.get(position));
mode.setTitle("Selected:"+Integer.toString(view.getCheckedItemCount()));
if(!isChecked)
imageAdapter.setCheckMark();
//imageAdapter.notifyDataSetChanged();
Toast.makeText(getApplicationContext(),Integer.toString(position),Toast.LENGTH_SHORT).show();
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.multiple_images, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId())
{
case R.id.multiple_image_select_all:
{
imageItems=imagePaths;
for(int i=0;i<imageItems.size();i++)
view.setItemChecked(i,true);
break;
}
case R.id.multiple_image_deleting:
{
if(imageItems!=null)
deleteItems(imageItems);
imageItems=null;
mode.setTitle("");
break;
}
}
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
Toast.makeText(getApplicationContext(),"Destroy",Toast.LENGTH_SHORT).show();
setAdapter(false);
//mode.finish();
}
});
}
private void setAdapter(boolean checked){
imageAdapter=new ImageAdapter(this,imagePaths,
R.layout.grid_item,R.id.grid_item_image,checked);
view.setAdapter(imageAdapter);
}
private void deleteItems(ArrayList<String> imageItems){
boolean isDeletingFolder=imagePaths.size()==imageItems.size();
for(String image:imageItems){
File file=new File(image);
file.delete();
imagePaths.remove(image);
}
setResult(RESULT_OK);
if(isDeletingFolder)
finish();
}
#Override
public void onItemClick(AdapterView<?> parent,View view,
int position, long id){
Toast.makeText(this, Integer.toString(position),Toast.LENGTH_LONG).show();
Intent intent=new Intent(this,ImageSlider.class);
intent.putStringArrayListExtra("images", imagePaths);
intent.putExtra("position", position);
startActivityForResult(intent, IMAGE_PATH_REQUEST);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==IMAGE_PATH_REQUEST){
if(resultCode==RESULT_OK){
imagePaths=data.getStringArrayListExtra("images");
setResult(RESULT_OK);
setAdapter(false);
setMultiChoiceMode();
}
else if(resultCode==RESULT_CANCELED){
setResult(RESULT_OK);
finish();
}
}
}
and here is my adapter
package com.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import com.example.vasylpaliy.mediaview.R;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.ArrayList;
public class ImageAdapter extends ArrayAdapter<String> {
private LayoutInflater mInflater;
private Picasso mPicasso;
private int typeLayout;
private int idImage;
private boolean checked;
public ImageAdapter(Context context, ArrayList<String> imagesPaths,
int typeLayout, int idImage, boolean checked) {
super(context, typeLayout,imagesPaths);
mInflater = LayoutInflater.from(context);
mPicasso = Picasso.with(context);
this.typeLayout=typeLayout;
this.idImage=idImage;
this.checked=checked;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(typeLayout, parent, false);
}
ImageView imageView = (ImageView) view.findViewById(idImage);
mPicasso.load(new File(getItem(position))).
resizeDimen(R.dimen.image_width, R.dimen.image_size).
centerCrop().into(imageView);
if(checked){
final CheckBox checkMark=(CheckBox)view.findViewById(R.id.checkImageMark);
checkMark.setVisibility(View.VISIBLE);
// checkMark.setButtonDrawable(R.drawable.checked24);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkMark.setButtonDrawable(!checkMark.isChecked() ? R.drawable.checked24_1 : R.drawable.checked24);
checkMark.setChecked(!checkMark.isChecked());
}
});
}
return view;
}
public void setCheckMark(){
checked=!checked;
}
}`
adapter view reuse it's views when scrolling
so you need a way to save state of the checked items in the list and also clear the views when reusing
so handle both cases checked and unchecked
if(checked){
checkMark.setVisibility(View.VISIBLE);
} else {
checkMark.setVisibility(View.GONE);
}
Also
i don't think checked variable should be global it should be specfic for each item in the list
It happen because GridView cache views and OnClickListener are not cleared.
You need handle false case
For example:
final CheckBox checkMark=(CheckBox)view.findViewById(R.id.checkImageMark);
if(checked){
checkMark.setVisibility(View.VISIBLE);
// checkMark.setButtonDrawable(R.drawable.checked24);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkMark.setButtonDrawable(!checkMark.isChecked() ? R.drawable.checked24_1 : R.drawable.checked24);
checkMark.setChecked(!checkMark.isChecked());
}
});
} else {
checkMark.setVisibility(View.GONE);
imageView.setOnClickListener(null);
}

Categories

Resources