Handle individual clicks on elements with recycleView - java

Im building a simple aplication with a recycleView/CardLayout, i followeed this tutorial.
I see many questions answered for the card click, but what i need is to handle diferent actions when the user clicks the title or the user clicks on the image in each card.
This is what i have at the moment:
public class SimiliarPlantsAdapter extends RecyclerView.Adapter<SimiliarPlantsAdapter.PlantViewHolder>{
ArrayList<Plant> plants = new ArrayList<Plant>();
Context context;
public static class PlantViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView plantName;
CheckBox plantCheck;
ImageView plantPhoto;
PlantViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
plantName = (TextView)itemView.findViewById(R.id.plantName);
plantCheck = (CheckBox)itemView.findViewById(R.id.plantCheck);
plantPhoto = (ImageView)itemView.findViewById(R.id.plantPhoto);
}
}
#Override
public PlantViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.similiar_photo_row, viewGroup, false);
PlantViewHolder pvh = new PlantViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PlantViewHolder holder, int position) {
holder.plantName.setText(plants.get(position).getSpecie());
holder.plantCheck.setText("Are you sure this is the plant?");
Log.d("foto",String.valueOf(holder.plantName));
String urlFoto = "http://10.0.2.2:3000/images/" + holder.plantName.getText().toString() + "/Thumbnail.jpg";
Picasso.with(context)
.load(urlFoto)
.resize(250, 250)
.into(holder.plantPhoto);
}
#Override
public int getItemCount() {
return plants.size();
}
public SimiliarPlantsAdapter(ArrayList<Plant> plants,Context context) {
this.plants = plants;
this.context = context;
}
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
}
MY Activity
public class SimiliarPhotos extends AppCompatActivity implements IResult {
RecyclerView rv;
LinearLayoutManager llm;
ArrayList<Plant> plants = new ArrayList<Plant>();
SimiliarPlantsAdapter adapter;
VolleyService mVolleyService;
IResult mResultCallback = null;
final String GETREQUEST = "GETCALL";
//login url connection
final String URL = "http://10.0.2.2:3000/plants";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_similiar_photos);
rv = (RecyclerView)findViewById(R.id.rv);
llm = new LinearLayoutManager(this);
llm.setAutoMeasureEnabled(true);
rv.setLayoutManager(llm);
initializeAdapter();
initVolleyCallback();
mVolleyService = new VolleyService(mResultCallback,this);
mVolleyService.getDataVolley(GETREQUEST,URL);
}
#Override
public void notifySuccess(String requestType, JSONObject response) {
Log.d("resposta",response.toString());
}
#Override
public void notifySuccess(String requestType, JSONArray response) {
Log.d("resposta",response.toString());
}
#Override
public void notifyError(String requestType, VolleyError error) {
Log.d("resposta",error.toString());
}
void initVolleyCallback(){
mResultCallback = new IResult() {
#Override
public void notifySuccess(String requestType, JSONObject response) {
}
#Override
public void notifySuccess(String requestType, JSONArray response) {
Plant plant;
Log.d("ENTERED","ENTEREDHERE1");
// iterate over the JSONArray response
for (int i=0; i < response.length(); i++) {
try {
JSONObject object = response.getJSONObject(i); // get the individual object from JSONArray
int id = Integer.parseInt(object.getString("id")); // get the unique identifier from the object
String specie = object.getString("specie"); // get the name of the specie from the object
String description = object.getString("description"); // get the description of the object
plant = new Plant(id,specie,description); // construct the object
Log.d("plant",String.valueOf(plant));
plants.add(plant); // add the object to the arraylist so it can be used on the cardLayout
} catch (JSONException e) {
Log.d("ENTERED",e.toString());
e.printStackTrace();
}
}
adapter.notifyDataSetChanged();
}
#Override
public void notifyError(String requestType, VolleyError error) {
Log.d("resposta",error.toString());
}
};
}
public void initializeAdapter(){
Log.d("plants",String.valueOf(plants.size()));
adapter = new SimiliarPlantsAdapter(plants,SimiliarPhotos.this);
rv.setAdapter(adapter);
}
}
The volley init is the request, not so important for the question, since i get the data correctly

First, you have to add the interface to handle the clicks in your Adapter and add it in your constructor :
public class SimiliarPlantsAdapter extends RecyclerView.Adapter<SimiliarPlantsAdapter.PlantViewHolder>{
private OnItemClickListener listener;
public interface OnItemClickListener {
void onTitleClicked(int position, String title, View clickedview);
void onImageClicked(int position, View clickedview);
}
}
public SimiliarPlantsAdapter(ArrayList<Plant> plants,Context context, OnItemClickListener listener ) {
this.plants = plants;
this.context = context;
this.listener = listener;
}
Now, you have to set these on your onClick method inside your onBindViewHolder:
holder.plantName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (onItemClickListener != null) {
onItemClickListener.onTitleClicked(holder.getAdapterPosition(), plants.get(position).getSpecie(), view);
}
}
});
holder.plantPhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (onItemClickListener != null) {
onItemClickListener.onItemClicked(holder.getAdapterPosition(), view);
}
}
});
}
}
And finally, implement the interface in your Activity:
public class SimiliarPhotos extends AppCompatActivity implements IResult, SimiliarPlantsAdapter.OnItemClickListener {
#Override
public void onTitleClicked(int position, String title, View clickedView) {
//Handle your title click here
}
#Override
public void onImageClicked(int position, View clickedView) {
//Handle your image click here
}
public void initializeAdapter(){
Log.d("plants",String.valueOf(plants.size()));
adapter = new SimiliarPlantsAdapter(plants,SimiliarPhotos.this, SimilarPhotos.this);
rv.setAdapter(adapter);
}

Related

How to flow Data from One RecyclerView to Another RecyclerView when an item in first RecyclerView is clicked?

Hi, I faced an issue here.. I was creating a chatbot in which user can type a text to send it and also can select a text out of the recommended texts
so I created two RecycleViews
My goal is - when the user selects one of the recommended text, then that text should appear in the Chatting RecycleView
here is my main Activity Class
public class Charts extends AppCompatActivity {
private static final String USER_KEY = "user";
private static final String BOT_KEY = "bot";
RecyclerView chart_recycle,auto_texts;
EditText message_text;
ImageView send_btn,mic_button;
ImageView setting_button;
ChartsAdapter chartsAdapter;
RecyclerView.LayoutManager linearLayout;
ArrayList<ChartModeClass> modeClassesArrayList = new ArrayList<>();
AutoAdapter autoAdapter;
RecyclerView.LayoutManager horizontal;
List<Texts> list = new ArrayList();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatting_hole);
message_text = findViewById(R.id.message_text);
send_btn = findViewById(R.id.send_btn);
mic_button = findViewById(R.id.mic_btn);
setting_button = findViewById(R.id.setting_button);
chart_recycle = findViewById(R.id.chart_recycle);
chart_recycle.setHasFixedSize(true);
auto_texts = findViewById(R.id.auto_texts);
auto_texts.setHasFixedSize(true);
linearLayout = new LinearLayoutManager(getApplicationContext(), RecyclerView.VERTICAL, false);
chart_recycle.setLayoutManager(linearLayout);
//Auto text
horizontal = new LinearLayoutManager(getApplicationContext(),RecyclerView.HORIZONTAL, false);
auto_texts.setLayoutManager(horizontal);
chartsAdapter = new ChartsAdapter(modeClassesArrayList, Charts.this);
chart_recycle.setAdapter(chartsAdapter);
//Auto texts
autoAdapter = new AutoAdapter(getApplicationContext(),list);
auto_texts.setAdapter(autoAdapter);
addInputs();
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(Charts.this);
mic_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bottomSheetDialog.setContentView(R.layout.record);
bottomSheetDialog.show();
}
});
message_text.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().length()==0){
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}else {
send_btn.setVisibility(View.VISIBLE);
mic_button.setVisibility(View.GONE);
}
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().isEmpty()){
// Toast.makeText(getApplicationContext(),"Enter text",Toast.LENGTH_LONG).show();
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}else {
send_btn.setVisibility(View.VISIBLE);
mic_button.setVisibility(View.GONE);
}
}
#Override
public void afterTextChanged(Editable editable) {
if (editable.toString().length()==0){
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}
}
});
send_btn.setOnClickListener(view -> {
if (message_text.getText().toString().isEmpty()) {
Toast.makeText(Charts.this, "Please enter text..", Toast.LENGTH_SHORT).show();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
returnResponse(message_text.getText().toString());
}
message_text.setText("");
});
}
#SuppressLint("NotifyDataSetChanged")
private void returnResponse(String message) {
modeClassesArrayList.add(new ChartModeClass(message, USER_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size()-1);
String url = "http://xxxxxxxxxxxxxxxx"+message;
String BASE_URL = "https://xxxxxxxxx";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitApi retrofitApi = retrofit.create(RetrofitApi.class);
Call<MessageModeClass> call = retrofitApi.getMessage(url);
call.enqueue(new Callback<MessageModeClass>() {
#Override
public void onResponse(#NonNull Call<MessageModeClass> call, #NonNull Response<MessageModeClass> response) {
if (response.isSuccessful()) {
MessageModeClass messageModeClass = response.body();
if (messageModeClass != null) {
modeClassesArrayList.add(new ChartModeClass(messageModeClass.getCnt(), BOT_KEY));
}
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
} else {
Toast.makeText(Charts.this, "response is null", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<MessageModeClass> call, #NonNull Throwable t) {
modeClassesArrayList.add(new ChartModeClass("No response check your network connection!", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}
});
}
#SuppressLint("NotifyDataSetChanged")
#Override
protected void onStart() {
super.onStart();
String lang = getIntent().getExtras().getString("lang");
if (lang.equals("english")){
modeClassesArrayList.add(new ChartModeClass("Hey welcome back am fema bot", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}else if (lang.equals("swahili")){
modeClassesArrayList.add(new ChartModeClass("Habari karibu miminni bot niliyetengenezw", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}else {
modeClassesArrayList.add(new ChartModeClass("Hey welcome back am fema bot", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}
}
private void addInputs() {
Texts text1 = new Texts("gender?");
Texts text2 = new Texts("gender equality");
Texts text3 = new Texts("what is good about females");
Texts text4 = new Texts("un goals");
Texts text5 = new Texts("about men");
list.addAll(Arrays.asList(new Texts[]{text1,text2,text3,text4,text5}));
}
}
here is my Adapter class class codes
public class AutoAdapter extends RecyclerView.Adapter<AutoAdapter.ViewHolderClass> {
Context context;
List<Texts> list;
public AutoAdapter(Context context, List<Texts> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public ViewHolderClass onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list,parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view);
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull ViewHolderClass holder, #SuppressLint("RecyclerView") int position) {
holder.input_text.setText(list.get(position).getText());
holder.input_text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// my stack
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public class ViewHolderClass extends RecyclerView.ViewHolder {
TextView input_text;
public ViewHolderClass(#NonNull View itemView) {
super(itemView);
input_text = itemView.findViewById(R.id.input_text);
}
}
}
You can add a list of your recommendations in another RecyclerView
Then in the ViewHolder of each item of the RecyclerView add Callback to listen on click events when a user clicks one of the item like the following
public class ViewHolderClass extends RecyclerView.ViewHolder {
private TextView input_text;
private final Callback callback; // custom callback
public ViewHolderClass(#NonNull View itemView, Callback callback) {
super(itemView);
this.callback = callback;
input_text = itemView.findViewById(R.id.input_text);
// now add onClickListener of the itemView to fire custom callback
itemView.setOnClickListener(view -> {
this.callback.onItemClick(getAdapterPosition());
});
}
// this is my custom callback for return click event
public interface Callback {
void onItemClick(int position);
}
}
Now inside your adapter add the callback from viewholder
public class AutoAdapter extends RecyclerView.Adapter<AutoAdapter.ViewHolderClass> {
private Context context;
private List<Texts> list;
private AutoAdapterCallback callback;
public AutoAdapter(Context context, List<Texts> list) {
this.context = context;
this.list = list;
}
public setCallback(AutoAdapterCallback callback) {
this.callback = callback;
}
#NonNull
#Override
public ViewHolderClass onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list,parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view, new ViewHolderClass.Callback() {
#Override
public void onItemClick(int position) {
// forward callback to adapter callback
if (callback != null) {
// get actual item from its position
final Texts texts = getItemByPosition(position);
// send to adapter callback
callback.onItemClick(texts);
}
});
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull ViewHolderClass holder, #SuppressLint("RecyclerView") int position) {
holder.input_text.setText(list.get(position).getText());
// I haven't used this inteady I added callback on viewholder side
// holder.input_text.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View view) {
// // my stack
// }
// });
}
#Override
public int getItemCount() {
return list.size();
}
// return Texts object by given position
public Texts getItemByPosition(int position) {
return this.list.get(position);
}
// add adapter callback to be called by viewholder
public interface AdapterCallback {
void onItemClick(Texts texts);
}
}
After that, now on your Activity you can easily listen on any item when a user clicks and get its corresponding Texts object from list as following:
//code ...
// here
//Auto texts
autoAdapter = new AutoAdapter(getApplicationContext(),list);
//set callback to listen for click events
autoAdapter.setCallback(new AutoAdapter.AutoAdapterCallback() {
#Override
public void onItemClick(Texts texts) {
// you can get your clicked item here
// now you can put texts object to another RecyclerView :)
}
});
auto_texts.setAdapter(autoAdapter);
//code ...

create recycler view in fragment?

i want create a fragment and have inside a recycler view for show products ...
but when i render it is show this error : RecyclerView: No adapter attached; skipping layout
below i copy my codes;
this code is for adapter class :
private ArrayList<Products> ProductsList;
private Context context;
public Adapter(ArrayList<Products> productsList, Context context) {
ProductsList = productsList;
this.context = context;
}
#Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.row_layout, parent, false);
return new MyHolder(v);
}
#Override
public void onBindViewHolder(MyHolder holder, final int position) {
Products products = ProductsList.get(position);
holder.txtName.setText(products.getName());
holder.txtPrice.setText("$ " + products.getPrice());
Picasso.get().load(Config.ipValue + "/images/" + products.getPhoto()).into(holder.imgV);
holder.imgV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.startAnimation(AnimationUtils.loadAnimation(context, android
.R.anim.slide_in_left));
}
});
}
#Override
public int getItemCount() {
return ProductsList.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView txtName;
TextView txtPrice;
ImageView imgV;
public MyHolder(View itemView) {
super(itemView);
txtName = itemView.findViewById(R.id.rowTxtProductName);
txtPrice = itemView.findViewById(R.id.rowTxtPrice);
imgV = itemView.findViewById(R.id.rowImgProduct);
}
}
and this one for web api class :
public class WebApiHandler {
Context context;
String apiLink = "";
ArrayList<Products> products = new ArrayList<>();
public WebApiHandler(Context context) {
this.context = context;
}
void apiConnect(String type) {
switch (type) {
case "getproducts": {
apiLink = Config.getProductsWebApi;
break;
}
}
ProgressDialog dialog = ProgressDialog.show(context, "Connecting...",
"please wait", false, false);
StringRequest request = new StringRequest(Request.Method.POST,
apiLink, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
dialog.dismiss();
showJson(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
dialog.dismiss();
}
});
RequestQueue queue = Volley.newRequestQueue(context);
queue.add(request);
}
private void showJson(String response) {
products.clear();
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("response");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
String id = object.getString("id");
String name = object.getString("name");
String description = object.getString("description");
String price = object.getString("price");
String photo = object.getString("photo");
Products p = new Products(id, name, description, price, photo);
products.add(p);
}
} catch (JSONException e) {
e.printStackTrace();
}
VerticalFragment.productsArrayList = products;
IData iData = (IData) context;
iData.sendData();
}}
and my fragment code :
public class VerticalFragment extends Fragment implements IData {
RecyclerView rcVertical;
WebApiHandler webApiHandler;
static ArrayList<Products> productsArrayList = new ArrayList<>();
public VerticalFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_vertical, container, false);
rcVertical = view.findViewById(R.id.rcVertical);
webApiHandler = new WebApiHandler(getContext());
webApiHandler.apiConnect("getproducts");
rcVertical.addOnItemTouchListener(new RecyclerTouchListener(getContext(), rcVertical,
new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
ProductActivity.products = productsArrayList.get(position);
startActivity(new Intent(getContext(), ProductActivity.class));
}
#Override
public void onLongClick(View view, int position) {
}
}));
return view;
}
#Override
public void sendData() {
Adapter adapter = new Adapter(productsArrayList, getContext());
rcVertical.setLayoutManager(new LinearLayoutManager((getContext())));
rcVertical.setItemAnimator(new DefaultItemAnimator());
rcVertical.setAdapter(adapter);
}}
i should say i create a interface and have one method i say it sendData
This is a common error when there is no adapter attached to recyclerview upon showing recyclerview. It will not cause any harm to your app, but you could avoid it by setting empty adapter without data, and later when you get your data, provide it to your adapter and notify it
Edit - Example added
Create setter for your list in adapter. After that, in your fragment make adapter global and in onCreateView make instance of your adapter and attach it to recyclerview
adapter = new Adapter(new ArrayList<>(), getContext());
rcVertical.setAdapter(adapter);
...Initialize recyclerview...
And then in your sendData interface put your loaded values in it
adapter.setData(productsArrayList);
adapter.notifyDataSetChanged();

Show wrong data when filtered RecyclerView item is clicked

I have a RecyclerView with edittext for search in my android app. When I search in it and click on an item, it shows wrong data.
I know why it happens but I don't know how to fix it. I have tried many things but still I have the problem. i am new in programming, please help :).
Here is the code of my Adapter.
public class ProjectAdapter extends RecyclerView.Adapter<ProjectAdapter.ProjectViewHolder> {
private Context mCtx;
private List<Project> projectList;
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public ProjectAdapter(Context mCtx, List<Project> projectList) {
this.mCtx = mCtx;
this.projectList = projectList;
}
#Override
public ProjectViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.project_list, null);
return new ProjectAdapter.ProjectViewHolder(view);
}
#Override
public void onBindViewHolder(ProjectViewHolder holder, int position) {
Project project = projectList.get(position);
holder.textViewProject.setText(project.getProject());
}
#Override
public int getItemCount() {
return projectList.size();
}
class ProjectViewHolder extends RecyclerView.ViewHolder {
TextView textViewProject;
public ProjectViewHolder(View itemView) {
super(itemView);
textViewProject = itemView.findViewById(R.id.textViewProject);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null){
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
mListener.onItemClick(position);
}
}
}
});
}
}
}
and this is my ListprojectActivity.java
public class ListprojectActivity extends AppCompatActivity implements ProjectAdapter.OnItemClickListener {
public static final String project_select = "project";
private static final String URL_PRODUCTS = "http://192.168.43.245/android_register_login/Api_1.php";
EditText editTextProject;
//a list to store all the products
List<Project> projectList;
//the recyclerview
RecyclerView recyclerView;
ProjectAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listproject);
//getting the recyclerview from xml
recyclerView = findViewById(R.id.recylcerViewProject);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
editTextProject = findViewById(R.id.EditTextProject);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
DividerItemDecoration itemDecoration = new DividerItemDecoration(this, layoutManager.getOrientation());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(itemDecoration);
//initializing the productlist
projectList = new ArrayList<>();
editTextProject.addTextChangedListener (new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
final String query = s.toString().toLowerCase().trim();
final ArrayList<Project> filteredList = new ArrayList<>();
for (int i = 0; i < projectList.size(); i++) {
final String text = projectList.get(i).getProject().toLowerCase();
if (text.contains(query)) {
filteredList.add(projectList.get(i));
}
}
recyclerView.setLayoutManager(new LinearLayoutManager(ListprojectActivity.this));
adapter = new ProjectAdapter(ListprojectActivity.this, filteredList);
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(ListprojectActivity.this);
adapter.notifyDataSetChanged();
}
#Override
public void afterTextChanged(Editable s) {
}
});
//this method will fetch and parse json
//to display it in recyclerview
loadProjects();
}
private void loadProjects() {
/*
* Creating a String Request
* The request type is GET defined by first parameter
* The URL is defined in the second parameter
* Then we have a Response Listener and a Error Listener
* In response listener we will get the JSON response as a String
* */
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_PRODUCTS,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
//converting the string to json array object
JSONArray array = new JSONArray(response);
//traversing through all the object
for (int i = 0; i < array.length(); i++) {
//getting product object from json array
JSONObject project = array.getJSONObject(i);
//adding the product to product list
projectList.add(new Project(
project.getInt("id_project"),
project.getString("project")
));
}
//creating adapter object and setting it to recyclerview
ProjectAdapter adapter = new ProjectAdapter(ListprojectActivity.this, projectList);
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(ListprojectActivity.this);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
//adding our stringrequest to queue
Volley.newRequestQueue(this).add(stringRequest);
}
#Override
public void onItemClick(int position) {
Intent detailMasalah = new Intent(this, ListproblemActivity.class);
Project projectclick = projectList.get(position);
detailMasalah.putExtra(project_select, projectclick.getProject());
startActivity(detailMasalah);
}
}
and project.java
public class Project {
private int id_project;
private String project;
public Project (int id_project, String project) {
this.id_project = id_project;
this.project = project;
}
public int getId() {
return id_project;
}
public String getProject() {
return project;
}
}
Try this
#Override
public void onBindViewHolder(ProjectViewHolder holder, int position) {
Project project = projectList.get(position);
holder.textViewProject.setText(project.getProject());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null){
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
mListener.onItemClick(position);
}
}
}
});
}
It happened because you are setting the listener in your ViewHolder class instead of your onBindViewHolder. As the viewholder is recycled, no new objects are created after some scrolling. The created object's click listener is bound to the item that first created it.
As Vishrut mentioned, you should move the listener to onBindViewHolder.

Making RecyclerView clickable not working

I have been working on making my RecyclerView list clickable. I have not successfully retrieve any results from clicks yet. I have searched through stackoverflow and youtube, but not understanding what I am implementing wrong. My Adapter is
Food Adapter
ublic class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
private Context mCtx;
private List<Food> foodList;
public FoodAdapter(Context mCtx, List<Food> foodList) {
this.mCtx = mCtx;
this.foodList = foodList;
}
#Override
public FoodViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.list_item, null);
FoodViewHolder foodView = new FoodViewHolder(view, mCtx, foodList);
return foodView;
}
#Override
public void onBindViewHolder(FoodViewHolder holder, int position) {
Food food = foodList.get(position);
holder.txtFoodTitle.setText(food.getFoodTitle());
holder.txtFoodDesc.setText(food.getFoodDesc());
holder.txtFoodLoc.setText(food.getFoodLoc() + ", CA");
holder.txtFoodAuthor.setText(food.getFoodAuthor());
holder.imageView.setImageDrawable(mCtx.getResources().getDrawable(food.getImage(), null));
}
#Override
public int getItemCount() {
return foodList.size();
}
class FoodViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView imageView;
TextView txtFoodTitle, txtFoodDesc, txtFoodLoc, txtFoodAuthor;
List<Food> foods;
Context ctx;
public FoodViewHolder(View itemView, Context ctx, List<Food> foods) {
super(itemView);
itemView.setOnClickListener(this);
this.ctx = ctx;
this.foods = foods;
imageView = itemView.findViewById(R.id.foodImg);
txtFoodTitle = itemView.findViewById(R.id.foodTitle);
txtFoodDesc = itemView.findViewById(R.id.foodDesc);
txtFoodLoc = itemView.findViewById(R.id.foodLoc);
txtFoodAuthor = itemView.findViewById(R.id.foodAuthor);
}
#Override
public void onClick(View view) {
int position = getAdapterPosition();
//Food food = this.foods.get(position);
Log.i(TAG, "Clicked!");
}
}
}
FragmentList
public class FragmentList extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_fragment_list, container, false);
RecyclerView recyclerView;
final FoodAdapter adapter;
final List<Food> foodList = new ArrayList<>();
recyclerView = v.findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new FoodAdapter(getActivity(), foodList);
recyclerView.setAdapter(adapter);
String url = "url";
StringRequest sr = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i(TAG, response);
try {
JSONArray foodResp = new JSONArray(response);
for (int i = 0; i < foodResp.length(); i++) {
JSONObject foodObj = foodResp.getJSONObject(i);
foodList.add(
new Food(
foodObj.getInt("u_id"),
R.drawable.ic_launcher_background,
foodObj.getString("mealTitle"),
foodObj.getString("mealDesc"),
foodObj.getString("cityName"),
foodObj.getString("userName")
));
}
if (adapter != null) {
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
Log.i(TAG, "Error: " + e.getMessage());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i(TAG, "err: " + error.toString());
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("data", "value");
return params;
}
};
Volley.newRequestQueue(getActivity()).add(sr);
return v;
}
One of the original videos I was watching showed it done with an ArrayList<>, but I already set up my RecyclerView with List. I do not imagine that that would matter. Any advice would be appreciated. Thanks!
Try to set Click Listener in your FragmentList.java.
Food Adapter
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
private Context mCtx;
private List<Food> foodList;
public FoodAdapter(Context mCtx, List<Food> foodList) {
this.mCtx = mCtx;
this.foodList = foodList;
}
public static class FoodViewHolder extends RecyclerView.FoodViewHolder {
ImageView imageView;
TextView txtFoodTitle, txtFoodDesc, txtFoodLoc, txtFoodAuthor;
//List<Food> foods;
//Context ctx;
public FoodViewHolder(View v) {
super(v);
imageView = itemView.findViewById(R.id.foodImg);
txtFoodTitle = itemView.findViewById(R.id.foodTitle);
txtFoodDesc = itemView.findViewById(R.id.foodDesc);
txtFoodLoc = itemView.findViewById(R.id.foodLoc);
txtFoodAuthor = itemView.findViewById(R.id.foodAuthor);
}
}
#Override
public FoodAdapter.FoodViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.list_item, parent, false);
return FoodViewHolder(view);
}
#Override
public void onBindViewHolder(FoodViewHolder holder, int position) {
Food food = foodList.get(position);
holder.txtFoodTitle.setText(food.getFoodTitle());
holder.txtFoodDesc.setText(food.getFoodDesc());
holder.txtFoodLoc.setText(food.getFoodLoc() + ", CA");
holder.txtFoodAuthor.setText(food.getFoodAuthor());
holder.imageView.setImageDrawable(mCtx.getResources().getDrawable(food.getImage(), null));
}
#Override
public int getItemCount() {
return foodList.size();
}
}
FragmentList
public class FragmentList extends Fragment {
RecyclerView recyclerView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_fragment_list, container, false);
final FoodAdapter adapter;
final List<Food> foodList = new ArrayList<>();
recyclerView = v.findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new FoodAdapter(getActivity(), foodList);
recyclerView.setAdapter(adapter);
String url = "url";
StringRequest sr = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i(TAG, response);
try {
JSONArray foodResp = new JSONArray(response);
for (int i = 0; i < foodResp.length(); i++) {
JSONObject foodObj = foodResp.getJSONObject(i);
foodList.add(
new Food(
foodObj.getInt("u_id"),
R.drawable.ic_launcher_background,
foodObj.getString("mealTitle"),
foodObj.getString("mealDesc"),
foodObj.getString("cityName"),
foodObj.getString("userName")
));
}
if (adapter != null) {
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
Log.i(TAG, "Error: " + e.getMessage());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i(TAG, "err: " + error.toString());
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("data", "value");
return params;
}
};
Volley.newRequestQueue(getActivity()).add(sr);
return v;
}
#Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
/* --- Adding the Listener here --- */
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View itemView, int position) {
//Food food = this.foods.get(position);
Log.i(TAG, "Clicked!");
}
}));
}
}
And this will be your RecyclerItemClickListener.java file:
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
GestureDetector mGestureDetector;
public interface OnItemClickListener{
void onItemClick(View view, int position);
}
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View childView = rv.findChildViewUnder(e.getX(),e.getY());
if(childView != null && mListener != null && mGestureDetector.onTouchEvent(e)){
mListener.onItemClick(childView, rv.getChildAdapterPosition(childView));
return true;
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
Hope it will help :)
You need to set the click listener on the specific element.
For example if you want to do something when you click on the image then :
You need to call holder.imageview.setOnClickListener(this);
Try this !!
If you want to set the click listener to the entire row, then you might want to set the click listener on the root element of your row item.
handling clicks for the entire item "the viewholder"
1. create custom listener
public class RecyclerClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
public void onLongItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && mListener != null) {
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
return true;
}
return false;
}
#Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
2. listen for clicks using our listener inside your
recyclerView.addOnItemTouchListener(
//use getActivity() if you are using fragment instead of MyActivity.this
new RecyclerClickListener(MyActivity.this, recyclerView, new RecyclerClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Food food= foodList.get(position);
//do whatever
}
#Override
public void onLongItemClick(View view, int position) {
// to be implement add to favourite
}
})
);
if you are listening to a specifc item inside the view holder.
1.create an inner interface inside your adapter and create an instance of it.
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(Food item);
}
//and also the constructor
public MyAdapter(List<Food> foodList,Context ctx,OnItemClickListener
listener){
// ......
this.mListener=mListener;
}
2.inside your viewholder class create setListener() method
public void SetListener(final Food item, final OnItemClickListener listener) {
mButton.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
3.inside you onBindView
#Override
public void onBindViewHolder(FoodViewHolder holder, int position) {
//...
viewHolder.setListener(foodList.get(position), mListener);
}
4.inside your activity or fragment
MyAdapter adapter=new MyAdapter(foodList,getActivity(),new MyAdapter.OnItemClickListener(){
#Override
public void onItemClick(Food item){
}
});

How to create a OnItemClickListener for custom list view when passing data from php using json

I am creating an app where a list of hotels will be shown, all the data is coming from MySQL using JSON and PHP, I created the custom list view by extending the base adapter to a custom one, but I am not able to implement a OnItemClickListener for the listview, as i want to show the Hotel Name of that row in Toast whenever the user clicks on a row of list view. I tried various example available on internet, but i just doesn't work.
Adapter
public class CustomListAdapterHotel extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private List<WorldsBillionaires> billionairesItems;
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
public CustomListAdapterHotel(Activity activity, List<WorldsBillionaires> billionairesItems) {
this.activity = activity;
this.billionairesItems = billionairesItems;
}
#Override
public int getCount() {
return billionairesItems.size();
}
#Override
public Object getItem(int location) {
return billionairesItems.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.list_hotel, null);
if (imageLoader == null)
imageLoader = AppController.getInstance().getImageLoader();
//NetworkImageView thumbNail = (NetworkImageView) convertView.findViewById(R.id.thumbnail);
TextView hotel_name = (TextView) convertView.findViewById(R.id.hotel_name);
TextView zone = (TextView) convertView.findViewById(R.id.zone);
TextView contact_person = (TextView) convertView.findViewById(R.id.contact_person);
TextView contact_number = (TextView) convertView.findViewById(R.id.contact_number);
TextView btc_direct = (TextView) convertView.findViewById(R.id.btcdirect);
// getting billionaires data for the row
WorldsBillionaires m = billionairesItems.get(position);
// name
hotel_name.setText(String.valueOf(m.getHotel_Name()));
zone.setText(String.valueOf(m.getHotel_Zone()));
contact_person.setText(String.valueOf(m.getContact_Person()));
contact_number.setText(String.valueOf(m.getContact_Number()));
btc_direct.setText(String.valueOf(m.getBtc_Direct()));
return convertView;
}
}
Model
public class WorldsBillionaires {
private String hotel_name,hotel_zone,contact_person,contact_number,btc_direct;
public WorldsBillionaires(String hotel_name, String hotel_zone, String contact_person, String contact_number, String btc_direct) {
this.hotel_name=hotel_name;
this.hotel_zone=hotel_zone;
this.contact_person=contact_person;
this.contact_number=contact_number;
this.btc_direct=btc_direct;
}
public WorldsBillionaires() {
}
public String getZone() {
return zone;
}
public void setZone(String zone) {
this.zone = zone;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
public String getHotel_Name() {
return hotel_name;
}
public void setHotel_Name(String hotel_name) {
this.hotel_name = hotel_name;
}
public String getHotel_Zone() {
return hotel_zone;
}
public void setHotel_Zone(String hotel_zone) {
this.hotel_zone = hotel_zone;
}
public String getContact_Person() {
return contact_person;
}
public void setContact_Person(String contact_person) {
this.contact_person = contact_person;
}
public String getContact_Number() {
return contact_number;
}
public void setContact_Number(String contact_number) {
this.contact_number = contact_number;
}
public String getBtc_Direct() {
return btc_direct;
}
public void setBtc_Direct(String btc_direct) {
this.btc_direct = btc_direct;
}
}
Main Activity
public class ShowHotel extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
// Billionaires json url
private ProgressDialog pDialog;
private List<WorldsBillionaires> worldsBillionairesList = new ArrayList<WorldsBillionaires>();
private ListView listView;
private CustomListAdapterHotel adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_hotel);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setLogo(R.mipmap.ic_launcher);
getSupportActionBar().setDisplayUseLogoEnabled(true);
listView = (ListView) findViewById(R.id.list);
adapter = new CustomListAdapterHotel(this, worldsBillionairesList);
listView.setAdapter(adapter);
pDialog = new ProgressDialog(this);
// Showing progress dialog before making http request
pDialog.setMessage("Loading...");
pDialog.show();
// Creating volley request obj
JsonArrayRequest billionaireReq = new JsonArrayRequest("http://192.168.247.1/AdminBihar/getHotel.php?zone="+methods.zone,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
hidePDialog();
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
WorldsBillionaires worldsBillionaires = new WorldsBillionaires();
worldsBillionaires.setHotel_Name(obj.getString("hotel_name"));
worldsBillionaires.setThumbnailUrl(obj.getString("image"));
worldsBillionaires.setHotel_Zone(obj.getString("zone"));
worldsBillionaires.setContact_Person(obj.getString("contact_person"));
worldsBillionaires.setContact_Number(obj.getString("contact_number"));
worldsBillionaires.setBtc_Direct(obj.getString("btc_direct"));
// adding Billionaire to worldsBillionaires array
worldsBillionairesList.add(worldsBillionaires);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(billionaireReq);
}
#Override
public void onDestroy() {
super.onDestroy();
hidePDialog();
}
private void hidePDialog() {
if (pDialog != null) {
pDialog.dismiss();
pDialog = null;
}
}
}
so after you get json data, in activity that shows your list do something like this:
public class DisplayListView extends AppCompatActivity {
ListView listView;
protected void onCreate(){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_list_view);
listView = (ListView) findViewById(R.id.listview);
hotelAdapter = new CustomListAdapterHotel (this, R.layout.row_layout);
listView.setAdapter(hotelAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
Model stuff = (Model) hotelAdapter.getItem(position);
String hotelName = stuff.getHotel_Name();
Toast.makeText(getApplicationContext(), hotelName, Toast.LENGTH_SHORT).show();
}
});
there, this worked for me :)

Categories

Resources